排他锁
- 排它锁,加锁后别的用户可以读取数据,但是不能更改数据
- mysql中, for update 是一种使用排它锁的方式
- 通过主键选中的。那么这个时候是行级锁
- 选中的条件不明确包含主键。这个时候会锁表
悲观锁
悲观锁的简介
- 悲观锁:当我们要对一个数据库中的一条数据进行修改的时候,为了避免同时被其他人修改,最好的办法就是直接对该数据进行加锁以防止并发。
- 悲观并发控制实际上是“先取锁再访问”的保守策略,为数据处理的安全提供了保证。
- 但是在效率方面,处理加锁的机制会让数据库产生额外的开销,还有增加产生死锁的机会,同时也会降低并发性能
悲观锁的实现
-
注意: 要使用悲观锁,我们必须关闭mysql数据库的自动提交属性。MySQL默认使用autocommit模式,也就是说,当你执行一个更新操作后,MySQL会立刻将结果进行提交。我们可以使用命令设置MySQL为非autocommit模式:set autocommit=0;
-
举一个栗子 ?
//开始事务 begin; //查询出商品库存信息,使用 for update 加上排它锁 select quantity from items where id=1 for update; //修改商品库存 update items set quantity=100 where id = 1; //提交事务 commit;
乐观锁
乐观锁的简介
- 乐观锁在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测
- 相对于悲观锁,在对数据库进行处理的时候,乐观锁并不会使用数据库提供的锁机制。一般的实现乐观锁的方式就是记录数据版本。
- 乐观锁不会产生任何锁和死锁,拥有更好的性能。
乐观锁的实现
-
通过一个单独的可以顺序递增的version字段,可以避免ABA问题:
//查询出商品信息,version = 1 select version from items where id=1 //修改商品库存为2 update items set quantity=2,version = 3 where id=1 and version = 2;
除了version以外,还可以使用时间戳,因为时间戳天然具有顺序递增性。
-
减小乐观锁力度,可以最大程度的提升吞吐率,提高并发能力:
//修改商品库存 update item set quantity=quantity - 1 where id = 1 and quantity - 1 > 0
悲观锁和乐观锁,该选择哪个?
- 乐观锁并未真正加锁,效率高。然而,如果锁的粒度掌握不好,更新失败的概率就会比较高,容易发生业务失败。
- 悲观锁依赖数据库锁,效率低。更新失败的概率比较低。
- 在高并发的业务场景下,悲观锁越来越少被使用了。
参考
- https://blog.csdn.net/jaryle/article/details/84332275
- https://juejin.im/post/5caaaa67e51d452b63241954
- https://blog.csdn.net/woshiluoye9/article/details/68954515