对一条数据加了读锁的情况下,这条数据有且只有添加读锁。排它锁、写锁是不行的
对一条数据加了写锁的情况下,这条数据不能添加写锁或者读锁。
锁分类 | 概述 | 样例 | 使用场景 |
悲观锁 | 悲观锁对数据被外界修改持有保守状态(悲观的) 因此在整个数据处理过程中,将数据处于锁定状态 往往依靠数据库提供的锁机制实现。 可以理解为:悲观锁,态度是悲观的,总是认为数据 在处理的时候会造成冲突,所以会把要修改的数据锁定 | 行锁,页锁,表锁,共享锁(读锁) 排它锁(写锁) | 写多,读少 保证数据安全 |
乐观锁 | 乐观锁认为数据在处理的过程中不会造成冲突 所以在数据进行提交更新的时候,才会正式对 数据的冲突与否进行检测,如果发生冲突,则 返回错误信息给用户,让用户决定如何去做 | 数据库乐观锁,缓存乐观锁 | 读多,写少,提高吞吐量 |
乐观锁吞吐量高的原因:只有在更新那条数据的一瞬间才会锁表
数据库乐观锁实现方案:
优点:简单高效,稳定可靠
缺点:并发能力低
1、通过版本号实现
修改表结构,新增version 版本号列。每次去更新库存的时候版本号+1。
update goods_info set amount = amount - #{buys} , version = version + 1
where code = #{code} and version = #{version}
2、通过状态控制
判断库存减去购买量大于0
update goods_info set amout = amout - #{buys}
where code = #{code} and amout-#{buys} >0
缓存乐观锁实现方案:
使用CAS(Compare and Swap)机制
步骤分析:读取数据--->比较数据---->更新数据
场景分析:秒杀场景
秒杀场景包含:抢票、商品秒杀、抢红包、在线预约。。。
秒杀的特点:
1、读多写少:比如抢票,200张票6000人来抢
2、短时高并发、负载压力大
3、资源竞争有限,不能多卖,不能少卖,不能重卖
根据秒杀特点可以选用乐观锁来控制库存操作。
service-----修改库存方法流程:
获取商品库存对象---获取商品库存---判断库存是否足够(库存是否小于当前购买量)--获取版本号
---带上版本号更新库存---更新失败的当前线程休眠(休眠时间随机)---递归调用修改库存方法
基于缓存实现秒杀---实现CAS机制