我目前正在阅读《高性能MySQL第二版》一书,试图了解MySQL中的事务隔离。
下面是他们对这两个事务隔离级别的解释。
读取已提交的
大多数数据库系统的默认隔离级别(但不是MySQL!)是READ COMMITTED。它满足了前面使用的隔离定义:事务只能看到已提交的事务所做的更改开始,并且在它完成之前,其他人不会看到它的更改坚信的这个级别仍然允许所谓的不可重复阅读这意味着您可以运行同一语句两次,然后看到不同的数据。
可重复读取
可重复读取解决了读取UNCOMITTED允许。它保证事务读取的任何行在同一事务中的后续读取中将"看起来相同",但在理论上,它仍然允许另一个棘手的问题:幻影阅读。简单地说,当您选择某个范围的行,另一个事务将新行插入该范围,然后您再次选择相同的范围;然后你会看到新的"幻影"一行InnoDB和Falcon通过多版本一致性控制,我们稍后将对此进行解释章REPEATABLE READ是MySQL的默认事务隔离数量InnoDB和Falcon存储引擎尊重此设置,你将在第6章中学习如何改变。一些其他存储发动机也是如此,但选择取决于发动机。
问题 :
1-在READ COMMITTED中,如果这个隔离级别意味着事务只能看到其他事务提交的更改,那么在同一事务中,如果运行相同的语句,为什么会看到不同的结果?这意味着以下内容吗?
START TRANSACTION;
SELECT balance FROM checking WHERE customer_id = 10233276;
UPDATE checking SET balance = balance - 200.00 WHERE customer_id = 10233276;
# >>> NEXT I MUST SEE THE NEW BALANCE, OR I AM WRONG ?
SELECT balance FROM checking WHERE customer_id = 10233276;
COMMIT;
2-在REPEATABLE READ中,如果此隔离级别允许幻影读取,那么它如何保证事务读取的任何行在后续读取中"看起来都一样"?幻影阅读不是反驳了这个级别的保证吗?
http://ronaldbradford.com/blog/understanding-mysql-innodb-transaction-isolation-2009-09-24/
可重复读取
会话1:
MariaDB [test]> DROP TABLE IF EXISTS transaction_test;
Query OK, 0 rows affected (0.22 sec)
MariaDB [test]> CREATE TABLE transaction_test(
-> id INT UNSIGNED NOT NULL AUTO_INCREMENT,
-> val VARCHAR(20) NOT NULL,
-> created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
-> PRIMARY KEY(id)
-> ) ENGINE=InnoDB DEFAULT CHARSET latin1;
Query OK, 0 rows affected (0.29 sec)
MariaDB [test]>
MariaDB [test]> INSERT INTO transaction_test(val) VALUES ('a'),('b'),('c');
Query OK, 3 rows affected (0.08 sec)
Records: 3 Duplicates: 0 Warnings: 0
MariaDB [test]> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)
MariaDB [test]> SELECT * FROM transaction_test;
+----+-----+---------------------+
| id | val | created |
+----+-----+---------------------+
| 1 | a | 2016-04-01 10:09:33 |
| 2 | b | 2016-04-01 10:09:33 |
| 3 | c | 2016-04-01 10:09:33 |
+----+-----+---------------------+
3 rows in set (0.00 sec)
MariaDB [test]> select sleep(50);
然后user2运行下一个代码:
MariaDB [test]> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)
MariaDB [test]> INSERT INTO transaction_test(val) VALUES ('x'),('y'),('z');
commit;
则用户1
MariaDB [test]> SELECT * FROM transaction_test;
+----+-----+---------------------+
| id | val | created |
+----+-----+---------------------+
| 1 | a | 2016-04-01 10:09:33 |
| 2 | b | 2016-04-01 10:09:33 |
| 3 | c | 2016-04-01 10:09:33 |
+----+-----+---------------------+
3 rows in set (0.00 sec)
MariaDB [test]>
只读
user1
SET SESSION tx_isolation='READ-COMMITTED';
TRUNCATE TABLE transaction_test;
INSERT INTO transaction_test(val) VALUES ('a'),('b'),('c');
MariaDB [test]> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)
MariaDB [test]> select sleep(60);
然后user2运行下一个代码:
MariaDB [test]> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)
MariaDB [test]> INSERT INTO transaction_test(val) VALUES ('x'),('y'),('zwfwfw');
Query OK, 3 rows affected (0.00 sec)
Records: 3 Duplicates: 0 Warnings: 0
MariaDB [test]> commit;
然后user1完成查询:
MariaDB [test]> SELECT * FROM transaction_test;
+----+--------+---------------------+
| id | val | created |
+----+--------+---------------------+
| 1 | a | 2016-04-01 10:28:08 |
| 2 | b | 2016-04-01 10:28:08 |
| 3 | c | 2016-04-01 10:28:08 |
| 4 | x | 2016-04-01 10:29:00 |
| 5 |
y | 2016-04-01 10:29:00 |
| 6 | zwfwfw | 2016-04-01 10:29:00 |
+----+--------+---------------------+
6 rows in set (0.00 sec)
在READ COMMITED中,无论您是否在事务中,都可以看到已提交的信息,因此不能保证信息的集成,因为它可以多次更改。相反,REPEATABLE READ禁止您在事务发生时修改(UPDATE)信息(完整性),但您可以添加信息(INSERT…)
根据我的理解,假设在开始这笔交易之前余额为1000。
交易内结果相同。
但在该事务之外,在启动事务并将其更新为"0"之后;balance=balance-200〃;,如果您在没有事务或任何其他事务的情况下运行select语句,则结果将如下所示-
-
若隔离级别为READ COMMITTED,那个么结果将为800。
-
若隔离级别为REPEATABLE READ,那个么结果为1000。