Mysql中select + update并发更新问题

一开始想的解决方案:

A、把select和update合并成一条sql

B、事务,用同一个事务包裹select+update的操作。

分析:并不是包上事务就万事大吉。因为如果同时有两个事务都分别select到了相同的记录,那么一样会发生有一方的更新会失败的问题。然后我再想到把事务的隔离级别设置为serializable,但是考虑到性能显然不现实。

我们知道innodb是支持行锁的,然后我就去查看看他的几种锁:读共享锁和写独占锁。

• 读共享锁

是通过SQL的LOCK IN SHARE MODE,例:

Select * from parent where name =‘jones’LOCK IN SHARE MODE;

如果事务A先获得了读共享锁,那么事务B仍然可以做读操作。但是必须等事务A commit或者roll back之后才可以更新或者删除加了读共享锁的行数据。-----但是这种锁并解决不了我们的问题,因为我们应该要再查询的时候就查到事务A commit或者roll back后的数据才是,才是数据别更新后的最新数据。

------如果想要解决上面的并发问题,采用读共享锁是不可以解决的

• 写独占锁

通过SQL的select…for update获得,例:

Select xxx from xxx for update;

Update xxx set xxx = #{xxx};

如果事务A先获得了某行写共享锁,那么事务B就必须等待事务A commit或者roll back之后才可以访问数据。

------如果想要解决上面的并发问题,采用写独占锁是可以解决的

另外这里特别提醒下:UPDATE/DELETE SQL尽量带上WHERE条件并在WHERE条件中设定索引过滤条件,否则会锁表,性能可想而知有多差了。因为

MySQL InnoDB默认Row-Level Lock,所以只有「明确」地指定主键,MySQL 才会执行Row lock (只锁住被选取的数据) ,否则MySQL 将会执行Table Lock (将整个数据表单给锁住)。


但是写独占锁是一种悲观锁机制,所以在大佬的指导下还有一种方式,可以避免悲观锁,就是乐观锁!

·乐观锁,类似CAS机制(应该采取的方式)

其实也很简单,首先在select的SQL不作任何修改,然后在update的SQL的where条件中加上select出来的。但是避免不了ABA问题。

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容