【问题标题】:Read Committed Vs Repeatable Reads in MySQL?MySQL 中的已提交读与可重复读?
【发布时间】:2016-07-13 04:24:59
【问题描述】:

我目前正在尝试了解MySQL中的事务隔离,阅读本书High Performance MySQL, 2nd Edition.

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

已提交阅读

大多数数据库系统的默认隔离级别 (但不是 MySQL!)是 READ COMMITTED 。它满足简单 前面使用的隔离定义:一个事务只会看到 由已经提交的事务所做的更改 开始,并且它的更改将不会对其他人可见,直到它 坚定的。这个级别仍然允许所谓的不可重复 读。这意味着您可以运行相同的语句两次并查看 不同的数据。

可重复阅读

REPEATABLE READ 解决了 READ 的问题 UNCOMMITTED 允许。它保证事务读取的任何行 在同一事务中的后续读取中将“看起来相同”, 但理论上它仍然存在另一个棘手的问题:幻读。 简而言之,当您选择某个范围的 行,另一个事务将新行插入范围,然后 您再次选择相同的范围;然后你会看到新的“幻影” 排。 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 中,如果此隔离级别允许幻读,它如何保证事务读取的任何行在后续读取中“看起来相同”?幻读不是反驳了这个级别的保证吗?

【问题讨论】:

    标签: mysql transactions isolation-level


    【解决方案1】:

    据我了解,假设在开始此交易之前余额为 1000。

    在开始交易并将其更新为“balance = balance - 200”后,如果您在交易中再次运行 select 语句,则结果将如下所示-

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

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

    【讨论】:

    • 错误答案。在同一个事务中,两个隔离级别只有在同一个事务中更新后才会产生 800。
    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

      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]>
      

      已提交读

      用户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);
      

      然后 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)
      

      【讨论】:

        猜你喜欢
        • 2016-12-21
        • 2017-08-24
        • 2018-12-06
        • 2011-05-12
        • 1970-01-01
        • 1970-01-01
        • 2019-06-01
        • 2020-08-30
        • 2013-08-20
        相关资源
        最近更新 更多