MySQL乐观锁是真正意义上的乐观锁?
在创作该文当天下午,看见某篇秒杀技术博客的文章说道利用mysql乐观锁提高并发(原文如下)
悲观锁虽然可以解决超卖问题,但是加锁的时间可能会很长,
会长时间的限制其他用户的访问,导致很多请求等待锁,
卡死在这里,如果这种请求很多就会耗尽连接,系统出现异常。
乐观锁默认不加锁,更失败就直接返回抢购失败,可以承受较高并发
突然发下自己对mysql乐观锁概念很是模糊,隐约知道有这个概念,便去网上搜索学习,然而在学习过程基本看到的都是:
乐观锁:
新增字段version或者类似字段
更新语句:update table1 set a=1, version = version + 1 where id = 2 and version = version // 1
悲观锁
更新语句:update table1 set a=1, version = version + 1 where id = 2 // 2
在看到这种解释和乐观锁实现方式后,认知观崩塌了。原因有2:
1. 都是MySQL数据库,使用的都是innodb引擎,都是update语句使用排他锁(for update),凭啥多了and version = version
就叫乐观锁?
2. 难道上面两条语句的效果不是一样?当语句1执行时开启事务,在事务提交之前其它事务只能阻塞,事务提交后其他事务拿到最新view重新加锁,此时的version = version有起到作用?
于是乎,我便思索再三,自己给了份解释给自己!
首先,这种解释下mysql的乐观锁本质还是悲观锁,因为update语句mysql默认都是排他锁,典型的悲观锁。
其次,这种解释下mysql的乐观锁只能说是一种思想或者境界,反正挺玄乎的一个东西,并不是大家传统观念中的乐观锁cas这种。
最后,这种解释下mysql的乐观锁的update语句应该是update table1 set a=1, version = version + 1 where id = 2 and version = #{version}
,某种意义上的确是可以提高并发能力。比如,MySQL并发量较大,假设5000个连接需要去执行这条语句,就像小蝌蚪奔向终点形成受精软一样,一定会有一个幸运儿(连接)首先开启事务,执行update,其他4999个连接都阻塞等待幸运儿提交事务,这个时候就不会满足where id = 2 and version = #{version}
条件而执行失败。否则的话剩余的4999个连接会重新竞争资源加锁,直到服务被打死,被老板开除,世界末日
ps: 上述栗子并不是很恰当,所以不要质疑谁会开启5000个mysql连接,为什么会世界末日。