背景
多人并发操作同一数据,可能导致数据不一致,数据不一致可是非常可怕的bug。
这是接上篇悲观锁讲解,
乐观悲观锁区别
- 并发冲突概率大的走悲观锁合适,概率小的走乐观锁
- 数据库开销不一样,悲观占用资源多特别是长事务的情况,影响了程序的并发访问性,乐观锁相反。
业务场景
工作流业务,如员工A操作工单审批通过,同时员工B也操作了相同的工单审批拒绝,
此时这个工单状态字段可能出现不一致情况。
问题来了
- 当应用的用户量上来了,就像今日头条从刚开始的几万,到如今上亿的用户量,APP操作的响应时间越来越慢,然后老板发话了,必须提高响应时间,让APP操作能毫秒级响应。
- 程序汪,接到命令就开始分析代码,发现mysql的select x for udpate 锁,有时占有数据库资源非常大。提供数据库的响应速度可是优化性能的杀手锏啊。
解决思路
- 程序汪说干就干,在业务单表里加了个lock_version字段 int类型,默认0, 0:未锁 1:锁住
- 先 select version from 业务单 where id=x ;
- 获得 version的值0,如果是1,表示已经被其他人锁了,直接退出操作或异常提示
伪代码走起
事务 begin------
相应的业务逻辑.......
【update 业务表 set 业务值, version=version+1 where id=#{id} and version=#{version};如果更新数据影响1行,返回true 否则返回false】
更新影响1行success【加锁OK】 ,lock_version_boolean=true 否则false【加锁失败】
if(!lock_version_boolean){
throw new Exception("亲,你并发异常了")
}
事务 end------
finally{
最后把锁重置 为update 0:未锁 状态【锁释放】
}
找了张图,大家理解下
version控制
注意
- 乐观锁思想在SVN,GIT就得到了应用,下载代表有version,提交代码是会更新version,当发现version不一致就提交失败。
- 在并发量不是很大情况for update完全够用,代码够简单。悲观锁代码稍微复杂点点,请根据场景正确选择。
- 乐观锁说白了就一个update的sql,请注意version参数别传错了,添加version字段到你核心业务表中,如电影系统内容表就是核心表。
如果觉得对你有帮助请关注,有错误请指点,下篇继续分析 【高性能缓存锁】
閱讀更多 程序汪汪 的文章