微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

MVCC 如何与 MySql 中的 Lock 一起工作?

如何解决MVCC 如何与 MySql 中的 Lock 一起工作?

我知道在MysqL中使用锁或者MVCC可以实现并发控制,比如repeatable-reading。 但我不知道 MVCC 如何避免幻读。在其他地方了解到一般是通过MVCC和Gap-Lock来实现的,但是我目前了解到的是MVCC不需要锁,即更新和删除都是使用undo-logs来实现的。 如果是这样,MVCC 和锁机制是如何协同工作的?

例如,为了避免幻读,MVCC 会在 T1 中的某些行上添加间隙锁吗? 如果是这样,MVCC在T2发生更新时是​​怎么做的,一般只是追加一个更新undo-log?或阻止它?

解决方法

MySQL(特别是 InnoDB)不支持 REPEATABLE-READ 锁定语句。例如,UPDATEDELETESELECT...FOR UPDATE。这些语句总是锁定最近提交的行版本,就好像事务隔离级别是 READ-COMMITTED。

您可以观察到这种情况:

mysql> create table mytable (id int primary key,x int);
Query OK,0 rows affected (0.05 sec)

mysql> insert into mytable values (1,42);
Query OK,1 row affected (0.02 sec)

mysql> start transaction;
Query OK,0 rows affected (0.00 sec)

mysql> select * from mytable;
+----+------+
| id | x    |
+----+------+
|  1 |   42 |
+----+------+

到目前为止,一切都很好。现在打开第二个窗口并更新值:

mysql> update mytable set x = 84;
Query OK,1 row affected (0.03 sec)
Rows matched: 1  Changed: 1  Warnings: 0

现在回到第一个窗口,由于 REPEATABLE-READ,非锁定读取仍然查看原始值,但锁定读取查看最近提交的版本:

mysql> select * from mytable;
+----+------+
| id | x    |
+----+------+
|  1 |   42 |
+----+------+
1 row in set (0.00 sec)

mysql> select * from mytable for update;
+----+------+
| id | x    |
+----+------+
|  1 |   84 |
+----+------+
1 row in set (0.00 sec)

mysql> select * from mytable;
+----+------+
| id | x    |
+----+------+
|  1 |   42 |
+----+------+
1 row in set (0.00 sec)

您可以根据需要来回多次,并且同一个事务可以返回两个值,具体取决于执行锁定读取还是非锁定读取。

这是 InnoDB 的一个奇怪的行为,但它允许读取不被阻塞。我使用了其他 MVCC 实现,例如 InterBase/Firebird,它们以不同的方式解决了这个问题。它会阻止读取,直到第二个窗口中的事务提交或回滚。如果回滚,则锁定读取可以读取原始值。如果其他事务提交,则锁定读取会出错。

InnoDB 对如何实现 MVCC 做出了不同的选择,以避免阻塞读取。但这会导致锁定读取必须查看最新提交的行版本的奇怪行为。

正如这首歌所说,“你不可能总是得到你想要的。”

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。