当前位置: 首页 > 知识库问答 >
问题:

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

童化
2023-03-14

我目前正在阅读《高性能MySQL,第二版》,试图理解MySQL中的事务隔离。

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

阅读提交

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

可重复读取

可重复读取解决了未提交读取所带来的问题。它保证了一个事务读取的任何行在同一个事务的后续读取中“看起来相同”,但是理论上它仍然允许另一个棘手的问题:幻像读取。简而言之,当您选择某个范围的行,另一个事务向该范围插入一个新行,然后您再次选择同一范围时,就会发生幻像读取;然后,您将看到新的“幻影”行。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;

2-在REPEATABLE READ中,如果这个隔离级别允许幻像读取,为什么它会保证事务读取的任何行在后续读取中“看起来相同”?幻像读取不反驳这个级别的保证吗?

共有3个答案

周伟泽
2023-03-14

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

冯星剑
2023-03-14

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

启动事务并将其更新为“balance=balance-200”后,如果在事务中再次运行select语句,则结果如下-

>

  • 若隔离级别为READ COMMITTED,那个么您将看到结果为800。

    如果隔离级别是可重复读取,那么您将看到结果为1000。

  • 微生烨然
    2023-03-14

    http://ronaldbradford.com/blog/understanding-mysql-innodb-transaction-isolation-2009-09-24/

    可重复阅读

    第一场会议:

        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;
    

    然后用户1完成查询:

    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)
    
     类似资料:
    • 问题内容: 我发生了繁重的数据库操作,这使我的数据库增加了大约10,000条记录。由于这可能需要很长时间,因此最好使用事务。 现在,我在事务内部进行了一些读取操作,并且由于直到endTransaction才提交插入操作,因此不会获取这些记录。我听说过一种叫做“事务隔离级别”的东西,它使我们也可以读取脏的(未提交的)记录。任何想法如何做到这一点? 问题答案: 我发现默认情况下,您将能够读取尚未提交的

    • 问题内容: 从这个甲骨文的Java教程: 当事务A检索行,事务B随后更新该行,事务A随后再次检索同一行时,将发生不可重复的读取。事务A两次检索同一行,但看到不同的数据。 脏读和不可重复读之间有什么区别?是不是同一回事?由于其他人的更新而阅读错误的结果? 提前致谢。 问题答案: 完全相同的页面解释了什么是脏读: 访问尚未提交的更新值被视为脏读,因为该值可能会回滚到其先前的值。如果读取的值稍后会回滚,

    • 那么,有没有其他方法来获得特定的键:值?

    • 不可重复读取和幻像读取有什么区别? 我已经阅读了维基百科上的隔离(数据库系统)文章,但我有一些疑问。在下面的示例中,会发生什么:不可重复读取和幻像读取? ####交易A # # # #输出: ####交易B ####交易A 另一个疑问是,在上面的例子中,应该使用哪个隔离级别?为什么?

    • pyspark新手,希望将csv文件读取到数据帧。似乎不能让人读。有什么帮助吗? ()中的Py4JJavaError回溯(最近一次调用)----

    • 有一系列关于Kafka交易和一次性交付的优秀文章 在其中一篇文章中,作者谈到了消费者: 因此,在消费者端,您有两个选项来读取事务性消息,通过“isolation.level”消费者配置来表示: read_committed:除了读取不属于事务的消息外,还可以在事务提交后读取属于事务的消息。 read_uncommitted(读取未提交):按偏移顺序读取所有消息,而无需等待事务提交。此选项类似于Ka