Mysql事务隔离级别与乐观锁的问题

发布于 2022-08-29 17:28:17 字数 475 浏览 20 评论 0

问题一:
当事务隔离级别设置为可重复读的时候,将所有select过的行都加了读锁,并且记录了版本号,当update 的时候们如果发现版本号变了,则事务失败回滚。不知道我这样理解是否正确?

问题二:
如果上面的理解正确,那是否innodb的可重复读这个隔离级别已经帮我们实现了乐观锁,所以并不需要手动通过版本或者时间戳来实现乐观锁,或者使用 悲观锁了?

问题三:
悲观锁 select ... for update 是增加了一个写锁? 所以所有的读写都会被block住?

问题四:
假设有事务A,先select 然后 update,事务B同样也是先select 然后再update
如果事务隔离级别为可重复读,事务A,B先后select加上了读锁,那么会不会因此而后面的update操作会互相block住,导致死锁?

问题一和问题四好像是矛盾的,因为如果问题四成立,事务会block住,也不会修改成功导致版本号不一致导致 回滚了。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

街道布景 2022-09-05 17:28:17

问题一:

可重复读(REPEATABLE READ)时,普通的 SELECT 并没有加读锁(话说 innodb 有读锁这种概念么?),而是由 mysql 缓存了 SELECT 的结果集,保证在这个事务里同样的 SELECT 语句得到的结果始终一致。所以也不存在 UPDATE 的时候版本号错误的问题,也不会因此回滚。

可以参考:http://dev.mysql.com/doc/refman/5.6/en/innodb-consistent-read.html

问题二:

对于可重复读级别的事务,因为你在事务中,只要不 COMMIT 任何修改都不会发生,也读不到别人更新的数据,所以你既无法加乐观锁,也无法在 COMMIT 前判断别人是否已经更新了数据,这使得你无论如何都实现不了乐观锁。

只有用 READ COMMITTED 才能实现你希望的乐观锁。

问题三:

FOR UPDATE 就是锁住所有选出来的记录,是一个写锁,所有的写都会被 block,普通的 SELECT 不会被 block。

问题四:

因为没有所谓的读锁存在,所以没有你想的这个问题存在。

箜明 2022-09-05 17:28:17

这个问题有些复杂,根据事务隔离的定义,可重复读是需要上读锁的:
wiki中文说明
wiki英文说明
也就是保证读取的内容不会发生改变。

但根据mysql的文档,innodb的实现机制是在读的时候,建立快照,以保证在单个事务内,读取的内容不会发生变化:mysql文档

那么就是产生了一些微妙的区别。。。虽然对结果来说没区别=。=
问题一二如同@Huan Du所说,没读锁所以不会失败,需要自己实现锁
问题四,不会有死锁

梦明 2022-09-05 17:28:17

回答下第一个和第二个问题作为采纳答案的补充,原先也没有在意,现在正好查到这一块了:
mysql默认的隔离级别是repeatable read,正常理解来说这个隔离级别就解决了不可重复读的问题,无需再用乐观锁了,但是实际情况是mysql并没有解决,它仅仅是保证多次读取时读的是同一数据,但是数据的准确性无法保证,所以还是需要自己去通过乐观锁来解决。(其它的数据库例如postgresql如果隔离级别是repeatable read的话是不需要乐观锁的)

更多参考:

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文