读已提交与MySQL中的可重复读?

Ade*_*lin 5 mysql transactions isolation-level

我目前正在尝试阅读MySQL High Performance MySQL,第二版,以了解MySQL中的事务隔离

这是他们对这两个事务隔离级别的解释。

读已提交

大多数数据库系统(而不是MySQL!)的默认隔离级别是READ COMMITTED。它满足了先前使用的隔离的简单定义:事务将仅看到事务在开始时已经提交的那些更改,并且其他更改直到提交后才对其他人可见。此级别仍允许进行不可重复的读取。这意味着您可以两次运行同一条语句并查看不同的数据。

可重复读取

REPEATABLE READ解决了READ UNCOMMITTED允许的问题。它保证了事务读取的任何行在同一事务的后续读取中都将“看起来相同”,但是从理论上讲,它仍然存在另一个棘手的问题:幻像读取。简而言之,当您选择某一行范围时,如果另一个事务将新行插入该行中,然后再次选择相同的范围,则可能发生幻读。您将看到新的“幻像”行。InnoDB和Falcon通过多版本并发控制解决了幻象读取问题,我们将在本章稍后解释。可重复读取是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;
Run Code Online (Sandbox Code Playgroud)

2-在“可重复读取”中,如果此隔离级别允许幻像读取,那么它如何保证事务读取的任何行在后续读取中都“看起来相同”?幻象阅读是否驳斥了该级别的保证?

zlo*_*ctb 8

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);
Run Code Online (Sandbox Code Playgroud)

然后 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;
Run Code Online (Sandbox Code Playgroud)

然后用户 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]>
Run Code Online (Sandbox Code Playgroud)

读提交

用户 1

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);
Run Code Online (Sandbox Code Playgroud)

然后 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;
Run Code Online (Sandbox Code Playgroud)

然后 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)
Run Code Online (Sandbox Code Playgroud)