背景
在高并发的场景中我们经常会让线程同步,如在秒杀商品时,我们需要对资源上锁来确保不发生超卖等问题,在单体应用中java已经为我们提供了相应的同步锁。然而,在分布式应用中这些锁将无能为力。
分布式锁的实现方式常用的有哪些呢?
1.Mysql数据库加锁方式
2.redis分布式锁
3.zookeeper分布式锁
Mysql数据库加锁方式
一、乐观锁
1.什么是乐观锁?
乐观锁就好比一个乐观的人,觉得别人不会来修改我的东西,所以我只需要在修改时比较版本号,有这个版本号就修改,没这个版本号就没有修改。
2. 乐观锁的实现实例
step1:
查询版本号
select version from user where uid=#{uid};
step2:
修改对应版本号的数据然后版本号也要加1
update user set name=#{newName} ,version=#{version}+1 where uid=#{uid} and version=#{version};
二、悲观锁
1.什么是悲观锁?
悲观锁就好比一个悲观的人,觉得别人随时都回来修改我的东西,所以要对数据库进行读取或修改时第一时间把对应行锁住(以下都是指INNODB存储引擎),让别人不能读取或修改,当自己处理完再释放锁。
2 悲观锁的分类
1)共享锁
共享锁就是允许多个线程同时获取一个锁,一个锁可以同时被多个线程拥有,而且加s锁的所有线程只能对资源进行读操作,如下
select user_name from user where uid=#{uid} lock in share model;
2)排它锁
排它锁,也称作独占锁,一个锁在某一时刻只能被一个线程占有,其它线程必须等待锁被释放之后才可能获取到锁。
select user_name from user where uid=#{uid} for update;
3)间隙锁
间隙锁就是不仅仅锁住所需要的行(如果锁住的这行不存在)还会锁住一个范围的行,这个范围依据锁住的这行而定。上下刚好是两个相邻索引叶节点的范围。包含下范围,不包含上范围。如下
select user_name from user where uid=#{uid} for update;
select user_name from user where uid>100 lock in share model;
select user_name from user where uid<100 for update;
select user_name from user where uid>100 and uid<120 for update;
间隙锁只会出现在辅助索引上,唯一索引和主键索引是没有间隙锁。间隙锁(无论是共享锁还是排他锁)只会阻塞insert操作。