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

9fkzdhlc  于 2021-07-08  发布在  Mysql
关注(0)|答案(3)|浏览(119)

我目前正在阅读High Performance MySQL, 2nd Edition.这本书,试图了解MySQL中的事务隔离
下面是他们对这两个事务隔离级别解释。
阅读已提交
大多数数据库系统(但不是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中,如果这个隔离级别允许幻影读取,那么它如何保证事务读取的任何行在后续读取中“看起来相同”呢?幻影读取不是否定了这个级别的保证吗?

dxxyhpgq

dxxyhpgq1#

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;


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

yi0zb3m4

yi0zb3m42#

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

zf9nrax1

zf9nrax13#

根据我的理解,假设余额是1000之前开始这笔交易。
内部交易结果将相同。
但是在此事务之外,在启动事务并将其更新为“balance = balance - 200”之后,如果您在没有事务或任何其他事务的情况下运行select语句,则结果将如下所示-
1.如果隔离级别为READ COMMITTED,则您将看到结果为800。
1.如果隔离级别为REPEATABLE READ,则您将看到结果为1000。

相关问题