Mysql自动对update加锁,那么乐观锁在mysql是怎么实现的?困扰我很久了!!

超超boy 2017-04-01 11:17:53
乐观锁是不对操作加锁,但是默认是加锁的?那乐观锁又是怎么实现的??
可以设置mysql对update这种语句不加锁么??
...全文
5590 10 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
青火coding 2020-08-12
  • 打赏
  • 举报
回复 4
其实这样理解是有问题的,mysql确实是有对单条的update语句默认加锁实现,但是只是仅仅的单条update。 比如UPDATE table1 SET num = num + 1 WHERE id=1;这样一条update语句,其实内部是分为两句,先查询到id = 1 的行的num值,再对num值进行更新,a = SELECT * FROM table1 WHERE id=1; UPDATE table1 SET num = a.num + 1 WHERE id=1;很显然,对num更新的操作进行了单条原子性的加锁,但是对id查询为1的操作并没有加锁。所以就会导致一个问题,在id = 1 查询完毕后,得到旧的num值,这时候另一个事务将num更新并提交。我们再对num进行更新,就会导致update的覆盖。所以如果不想发生这种情况就需要对前面id = 1的加共享锁或者是排他锁。 再者就是使用乐观锁,使用update t_goods set status=2,version=version+1 where id=#{id} and version=#{version}; 在更新的时候会去找当前的version值,如果一致则更新。a = select * from t_goods where id=#{id} and version=#{version} update t_goods set status=2,version=a.version+1 where id=#{id} and version=#{version};如果中途被改变,则第二条更新语句的version修改,无法更新。第一条查询语句只是查询到对应version的值用于对第二条修改语句的更新。。 我也在学, 希望我说的够清晰 , 所以是有加锁和乐观锁 两种方式保证并发的更新
GG22G2 2021-06-19
  • 举报
回复
@青火coding 感谢,收获匪浅,但我有个疑问希望您解答。即使加上了version,update语句还是一个查询再更新的过程,如果有update1,update2两个sql同时执行,那么按照update前会先select,假设恰好是按照select1, select1,update1,update2这样的顺序执行,那查出的数据,也就是a.version是相同的值,做加1操作不还是有丢失的风险。
青火coding 2021-06-20
  • 举报
回复 1
@GG22G2 select1和update1的两个语句都是用一个where的,也就是说如果update1已经将version进行了修改,那update2的where将无法匹配,那么update2自然也无法执行。 比如最初version是1,根据update1进行了修改变了2。然后update2的语句就变成,update t_goods set status = 2,version = 1+1 where id=#{id} and version = 1(是最初的值,但是已经被update1进行修改成了2),所以update2会失败
qq_28355497 2020-04-10
  • 打赏
  • 举报
回复 1
引用 5 楼 超超boy 的回复:
[quote=引用 4 楼 a675697174 的回复:] 我知道你的困惑, 我也有跟你一样的困惑, 请问你现在明白了吗。。
其实这个困惑是两件事, mysql对update语句加锁, 是保证了语句级别的原子性. 而 乐观锁就是另一回事了, 举个例子: 有一个商品表,有个字段 商品数量, 买了商品, 就把商品表里的数量减1, 增加库存就把数量加1. 那么有这么一个场景: A(一个商家), B(一个消费者) A进了10件货,count = count+10 B买了5件商品, count = count -5. 那么当这两件事一块来的时候, count 怎么保证事务性?? 乐观锁的实现是在update的时候,判断下version, version不对, 我再读一遍, count最终会一致的.[/quote] 说的很对,撸主解答了我的疑惑
jimcarol 2019-05-02
  • 打赏
  • 举报
回复
嗯嗯,是这样的
超超boy 2019-03-12
  • 打赏
  • 举报
回复
引用 4 楼 a675697174 的回复:
我知道你的困惑, 我也有跟你一样的困惑, 请问你现在明白了吗。。
其实这个困惑是两件事, mysql对update语句加锁, 是保证了语句级别的原子性. 而 乐观锁就是另一回事了, 举个例子: 有一个商品表,有个字段 商品数量, 买了商品, 就把商品表里的数量减1, 增加库存就把数量加1. 那么有这么一个场景: A(一个商家), B(一个消费者) A进了10件货,count = count+10 B买了5件商品, count = count -5. 那么当这两件事一块来的时候, count 怎么保证事务性?? 乐观锁的实现是在update的时候,判断下version, version不对, 我再读一遍, count最终会一致的.
jimcarol 2018-08-31
  • 打赏
  • 举报
回复
我知道你的困惑, 我也有跟你一样的困惑, 请问你现在明白了吗。。
超超boy 2017-04-01
  • 打赏
  • 举报
回复
引用 1 楼 rucypli 的回复:
乐观锁是要在程序代码实现的 对表加一个时间戳的列 先select出来id和时间戳 然后再用id和时间戳来更新这行记录 如果未能更新 说明时间戳变动,已被人更改
你说的我都知道,你没有看懂我的困惑,不过我现在好像想通了,你帮我看看是不是2楼我理解的那样。主要就是自动提交,每个语句是一个事务。 谢谢。。
超超boy 2017-04-01
  • 打赏
  • 举报
回复
我之前混淆了事务和锁的定义。 以mysql为例:在乐观锁中设置的是自动提交的,也就是一个语句就是一个事务,至于事务级别可能是提交读或是未提交读也是可以的。 基本步骤是: 1.查询出商品信息 select (status,status,version) from t_goods where id=#{id} 2.根据商品信息生成订单 3.修改商品status为2 update t_goods set status=2,version=version+1 where id=#{id} and version=#{version}; 乐观锁中,上边的每一个语句就是一个小事务,select都是可以随便读的,只有在更新时检查。 不知道是不是我理解的这样???希望指正。。。
rucypli 2017-04-01
  • 打赏
  • 举报
回复
乐观锁是要在程序代码实现的 对表加一个时间戳的列 先select出来id和时间戳 然后再用id和时间戳来更新这行记录 如果未能更新 说明时间戳变动,已被人更改

56,912

社区成员

发帖
与我相关
我的任务
社区描述
MySQL相关内容讨论专区
社区管理员
  • MySQL
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧