我目前正在尝试理解MySQL中的事务隔离,阅读本书High Performance MySQL, 2nd Edition.
以下是他们对这两个事务隔离级别的解释。
READ COMMITTED
大多数数据库系统的默认隔离级别 (但不是MySQL!)是READ COMMITTED。它满足了简单 前面使用的隔离定义:只能看到一个事务 由那些已经提交的事务所做的更改 开始了,直到它有其他人才能看到它的变化 承诺。这个级别仍然允许所谓的不可重复 读。这意味着您可以运行相同的语句两次并查看 不同的数据。
REPEATABLE READ
REPEATABLE READ解决了READ的问题 安排允许。它保证事务读取的任何行 在同一交易中的后续读取中“看起来相同”, 但理论上它仍然允许另一个棘手的问题:幻像读取。 简而言之,当您选择某个范围时,可能会发生幻像读取 行,另一个事务在该范围中插入一个新行,然后 你再次选择相同的范围;然后你会看到新的“幽灵” 行。 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中,如果此隔离级别允许幻读,那么为什么transactin读取的任何行将在后续读取中“看起来相同”? phanton读取不反驳此级别的保证吗?
答案 0 :(得分:3)
http://ronaldbradford.com/blog/understanding-mysql-innodb-transaction-isolation-2009-09-24/
<强> REPEATABLE-READ 强>
会话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]>
<强> READ-COMMITTED 强>
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)
答案 1 :(得分:2)
根据我的理解,假设在开始此交易之前余额为1000。
启动交易并将其更新为“balance = balance - 200”后,如果再次运行select语句,则结果将如下所示 -
如果隔离级别为READ COMMITTED,那么您将看到结果为800。
如果隔离级别是REPEATABLE READ,那么您将看到结果为1000。
答案 2 :(得分:2)
在READ COMMITED中,您会看到已提交的信息,无论您是否处于事务中,因此无法保证信息的集成,因为它可能会多次更改。而不是这是REPEATABLE READ,它禁止您在事务发生时修改(UPDATE)信息(完整性),但是您可以添加信息(INSERT ...)