在MySQL中读取提交的Vs可重复读取?

时间:2016-03-25 11:59:19

标签: mysql transactions isolation-level

我目前正在尝试理解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读取不反驳此级别的保证吗?

3 个答案:

答案 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语句,则结果将如下所示 -

  1. 如果隔离级别为READ COMMITTED,那么您将看到结果为800。

  2. 如果隔离级别是REPEATABLE READ,那么您将看到结果为1000。

答案 2 :(得分:2)

在READ COMMITED中,您会看到已提交的信息,无论您是否处于事务中,因此无法保证信息的集成,因为它可能会多次更改。而不是这是REPEATABLE READ,它禁止您在事务发生时修改(UPDATE)信息(完整性),但是您可以添加信息(INSERT ...)