共计 3302 个字符,预计需要花费 9 分钟才能阅读完成。
这篇文章主要讲解了“怎么理解 Innodb 一致性非锁定读”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着丸趣 TV 小编的思路慢慢深入,一起来研究和学习“怎么理解 Innodb 一致性非锁定读”吧!
一致性非锁定读指 InnoDB 通过多版本控制 (MVCC) 的方式在某个时间点通过查询数据库快照数据来读取数据。
在 RR 事务隔离级别下,在一个事务中第一次 (select 读) 数据的时候创建快照,快照是在第一次 select 之前所有提交的数据的最新版本的数据,在此事务结束之前,select 到的数据是一致的(快照)。
注意:Begin 和 start transaction 开启事务的时候快照并没有创建,而是第一次 select 读数据时候创建。
如下:
Session A
Session B
Session A drop table t;
Session A create table t(x int primary key);
Session A insert into t values (1),(5);
Session A begin;
Session A select @@tx_isolation;
+—————–+
| @@tx_isolation |
+—————–+
| REPEATABLE-READ |
+—————–+
Session A select * from t where x=5 for update;
上面的 for update 进行的锁定读,此时并没有创建 read view 注意:for update 和 lock in share mode 都是锁定读,此时并不会创建快照
Session B begin;
Session B select @@tx_isolation;
+—————–+
| @@tx_isolation |
+—————–+
| REPEATABLE-READ |
+—————–+
1 row in set (0.00 sec)
Session B insert into t select 3;
Session B commit;
Session A select * from t; # 此时才创建 read view 生成快照
+—+
| x |
+—+
| 1 |
| 3 |
| 5 |
+—+
你可能会发现 RR 隔离级别,不是应该看不到其他事务修改的数据吗?这正是因为 begin 开启一个事务,不是 begin 的时候创建 read view,而是第一次进行快照读的时候才创建
在 innodb 的 READ COMMITTED 和 REPEATABLE READ 隔离级别下执行 select 操作,默认模式就是一致性读。
一致性读不会对访问的表加任何锁,因此,其他会话可以任意的修改对象数据而不会影响当前会话的一致性读。
在 RR 隔离级别下,某个时间点开启一个事务 T1 查询表的数据,接着开启另外一个新的事务 T2 对其 delete、update、insert 数据并且 commit 成功后,在 T1 中无法看到 T2 修改并且提交的结果。
注意:快照读主要适用于在一个事务中的 select 语句。所以事务中的 DML 语句是可以看到其他 session 中的事务的更新的,即时 SELECT 并不能看到这些
例如,同时开启事务 T1、T2、T3, 在 T1 中删除或者修改表 t 的数据,在 T2 中 select 查询的结果(快照读)是之前的 t 的数据(T2 事务开启时间点的前 t 的数据), 但 T3 对表 t 修改或者删除可能会影响刚才 T1 提交的行。
下面的例子中:Session A 只有在 Session B 的 insert 操作 commit 完成,并且 Session A 自身事务 commit 之后才能看到 Session B 插入的数据
可以使用 READ COMMITTED 或 locking read(SELECT * FROM t LOCK IN SHARE MODE;)来查看表最新的数据。
一致性读不适用于特定的 DDL 语句如 DROP TABLE、ALTER TABLE。
另外,对于 INSERT INTO … SELECT, UPDATE … (SELECT)和 CREATE TABLE … SELECT 操作,虽然后面的 select 未指定 FOR UPDATE 或 LOCK IN SHARE MODE,但此时的 select 和 READ COMMIT 隔离级别下的 SELECT 一样, 读取最新版本数据(使用的当前读)。
如下:
Session A
Session B
ession A create table a (x int primary key,y int);
Query OK, 0 rows affected (0.17 sec)
# 开启一个新事务
Session A begin;
Query OK, 0 rows affected (0.00 sec)
Session A select * from a;
Empty set (0.00 sec)
# 插入数据
Session A insert into a select 1,2;
Query OK, 1 row affected (0.00 sec)
Records: 1 Duplicates: 0 Warnings: 0
# 当前事务能看到 insert 的数据
Session A select * from a;
+—+——+
| x | y |
+—+——+
| 1 | 2 |
+—+——+
1 row in set (0.00 sec)# 暂时不 commit
# 在 A 提交之前,B 开启事务 Session B begin;
Query OK, 0 rows affected (0.00 sec)
# 此时查询表 a 的数据,一致性非锁定读,读到的是事务开启前已经提交的数据,因为 B 的事务开始的时候 A 事务还没有提交,故 A 中 insert 的数据不会显示
Session B select * from a;
Empty set (0.00 sec)
#session A 提交上面的事务 Session A commit;
Query OK, 0 rows affected (0.00 sec)
# 在 B 中 select 查询,依旧进行的是快照读,故看不到数据 Seesion B select * from a;
Empty set (0.00 sec)
Seesion B select * from aa;
Empty set (0.00 sec)
#INSERT INTO … SELECT * FROM A; 操作
Seesion B insert into aa select * from a;
Query OK, 1 row affected (0.00 sec)
Records: 1 Duplicates: 0 Warnings: 0
Seesion B select * from a;
Empty set (0.00 sec)
# 发现直接 select 表 a 还是查不到数据,而 aa 表能看到数据
Seesion B select * from aa;
+—+——+
| x | y |
+—+——+
| 1 | 2 |
+—+——+
1 row in set (0.00 sec)
# 使用 lock in share mode 或 for update 进行当前读能看到表 a 的数据
Seesion B select * from a lock in share mode;
+—+——+
| x | y |
+—+——+
| 1 | 2 |
+—+——+
1 row in set (0.00 sec)
Seesion B select * from a;
Empty set (0.00 sec)
Seesion B select * from a for update;
+—+——+
| x | y |
+—+——+
| 1 | 2 |
+—+——+
1 row in set (0.00 sec)
当 innodb_locks_unsafe_for_binlog 选项为 1 时(关闭 GAP 锁),在 READ UNCOMMITTED, READ COMMITTED, REPEATABLEREAD 隔离级别下,select 查询表的数据,不会对数据进行锁定,而都是一致性读。
感谢各位的阅读,以上就是“怎么理解 Innodb 一致性非锁定读”的内容了,经过本文的学习后,相信大家对怎么理解 Innodb 一致性非锁定读这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是丸趣 TV,丸趣 TV 小编将为大家推送更多相关知识点的文章,欢迎关注!