目录
1. 使用@Async多线程操作数据库担心数据不一致引发的思考
其实这个问题一些新手CRUD程序员也会想到, 下面我模拟一个场景简单还原一下
问题还原: 现存在一张mysql的表, 表中有state字段表示状态(激活\非激活\激活中), 现在需要一个异步的方法去执行激活操作. 执行前需要判断该行state字段是否处于[非激活]状态, 若处于[非激活状态]则进行激活操作, 然后将状态设设置为[激活中], 等激活完成后更新状态为[已激活], 否则不进行激活操作.
我的担心: 因为该操作是异步的, 假设有A和B两个线程, 如果A线程执行激活操作, 那么程序会去执行更新操作: 将state更新为[激活中], 我担心的是更新state字段为[激活中]这套动作还没完成时, B线程读取了该行state字段, 结果肯定是[非激活], 然后B线程也会执行激活操作, 这样A和B线程都执行了激活操作, 这样就存在问题了. 如果这个操作不是激活而是其他操作比如转账, 这样就肯定不行了.
解决方案: 查阅了相关资料比如这位老铁的文章就讲的很好, 这个图片我是太喜欢了搬过来装装B
图片来自:weixin_39559071
还有这篇关于行锁的介绍, 还有这位老哥的文章描述了一些行锁需要避免的坑, 还有这位大佬, 写的都很好, 让我受益匪浅, 我就不造轮子了, 在这引用weixin_39559071 中的一句过来方便回忆翻阅
对于UPDATE、DELETE、INSERT语句,InnoDB会自动给涉及数据集加排他锁(X) MyISAM在执行查询语句SELECT前,会自动给涉及的所有表加读锁,在执行增、删、改操作前,会自动给涉及的表加写锁,这个过程并不需要用户干预
这样看来我的担心就是多余的啦, 因为InnoDB会自动添加行锁, 那么上述的担心:A线程更新state字段操作未完成, 因为行锁存在, B线程只能乖乖等A线程更新state字段完成四释放锁后才能进行读取.