MySQL 锁与MVCC
前提概念
数据库并发三种场景
- 读-读:不存在任何问题,无需并发控制
- 读-写:有隔离性问题,可能出现脏读、不可重复度和幻读
- 写-写:可能存在更新丢失问题,比如第一类更新丢失,第二类更新丢失
悲观锁和乐观锁
- 乐观锁和悲观锁是一种锁设计思想
悲观锁(PCC)
- 默认数据被外界访问时,必然产生冲突,以加锁方式,保证同一时间只有一个线程访问到数据,实现排他性
解决读-写冲突和写-写冲突
悲观锁的实现
利用数据库本身提供的锁实现
- 外界访问数据,首先向数据库申请该数据的锁
- 若成功,操作该数据,其他客户端无法操作该数据
- 若失败,代表同一时间其他客户端获得该锁,必须等待期释放锁
优点:适合于写多读少,提高数据安全性
缺点:加锁增加系统开销,数据吞吐量低,不适合读多写少下使用
乐观锁(OCC)
- 数据提交更新时,对数据冲突与否进行检测,若冲突则返回冲突信息,让用户决定去做下一步,比如重试,直至成功
解决写-写场景,无锁方式解决并发问题
CAS思想
- CAS指令需要3个操作数,分别是内存位置V,旧的预期值A和新值B,CAS指令执行时,当读取的内置位置V的现值等于旧预期值A时,处理器会将新值B去更新内置位置V的值。否则不执行更新。
乐观锁的实现(基于CAS思想设计)
- 数据版本(version)实现
- 表中添加version字段,每行数据的版本标识,每次对数据操作提交version+1
- 当对数据更新提交时,将取得version与数据库中的version比对,若大于则表示没有其他线程修改过此数据。否则其他线程修改过,返回冲突信息,让用户决定下一步动作
update table set num = num + 1, version = version + 1 where version = #{version} and id = #{id}
- 时间戳实现
- 表中添加update_time字段使用时