本文共 802 字,大约阅读时间需要 2 分钟。
通过试验,发现某种程度上已经理解了自己的问题。
我之前被关于事务隔离级别错误信息误导,认为REPEATABLE-READ级别和SERIALIZABLE级别能解决丢失更新的问题,然而实际是不能的。
因为mysql的select ... from table;语句 不管哪种隔离级别都是不会阻塞的,
事务A读取 id为1 number = 3 ,执行更新操作 number设为1;
事务B读取 id为1 number = 3, 执行+1操作 更新--进入阻塞
在隔离级别下只有在更新数据时才会等待写锁(排它锁)的释放,所以我多个线程可以同时读取到number=3,基于此进行修改就必然会导致丢失更新。
所以解决办法为程序中加入悲观锁 或 乐观锁 机制。
悲观锁采用的是 select ... for update,
事务A: select ... for update,执行更新操作,
事务B: select ... for update --阻塞
这时事务B读取操作将无法执行,只有当事务A的commit完成,事务B才可以继续执行,相当于采用串行一个个执行。
乐观锁常用的是版本控制或时间戳控制,
事务A:执行 此时版本为 1;执行完update ...set version=2 where version = 1;
事务B:执行 此时版本为 1;执行完update ...set version=2 where version = 1;
这时候事务B发现version=1已经不存在了,因为事务A首先执行完更新了数据库,把version字段设为了2,这样就会导致该事务提交失败,需要我们在程序中判断异常情况下如何继续操作。
以上就是我当前的理解,至于mysql本身支持的MVCC(多版本并发控制)还不知道怎么用,乐观锁的异常处理也不太清楚具体要怎么实现,可能是要根据具体的业务场景采用不同的处理手段吧。
转载地址:http://wfnzx.baihongyu.com/