1.基于redisson实现(本质redis)
原理:
SET my:lock 随机值 NX PX 30000
这个的NX的意思就是只有key不存在的时候才会设置成功,PX 30000的意思是30秒后锁自动释放。别人创建的时候如果发现已经有了就不能加锁了。
释放锁就是删除key,但是一般可以用lua脚本删除,判断value一样才删除
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.16.4</version>
</dependency>
package com.zl.shop.config;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RedissonConfig {
@Bean
public RedissonClient redissonClient(){
Config config=new Config();
config.useSingleServer()
.setAddress("redis://127.0.0.1:6379")
.setPassword("zl199463");
RedissonClient client=Redisson.create(config);
return client;
}
}
@Autowired
private RedissonClient redissonClient;
/**
* @description: 抢购-redission分布式锁优化
* @author: zhanglei
* @createTime: 2021/10/28 15:14
**/
@Override
@Transactional(rollbackFor = Exception.class)
public ResultBean goodKill4(Integer goodId, Integer userId) {
String errMsg = "";
String key = new StringBuffer().append(goodId).append(userId).append("-redisLock").toString();
RLock lock = redissonClient.getLock(key);
try {
boolean m = lock.tryLock(10,10,TimeUnit.SECONDS);
if(m) {
//判断当前用户是否抢购过该商品
Integer count = killSuccessMapper.selectCount(new LambdaQueryWrapper<ItemKillSuccess>()
.eq(ItemKillSuccess::getUserId, userId).eq(ItemKillSuccess::getKillId, goodId));
if (count == 0) {
//校验库存
GoodVo goodVo = itemKillMapper.goodDetail(goodId);
if (goodVo != null && goodVo.getCanKill() == 1) {
//更新库存
int row = itemKillMapper.killOne(goodId);
if (row > 0) {
//更新成功,生成订单
generateOrder(goodVo, userId);
}
} else {
errMsg = "目前无法抢购";
}
} else {
errMsg = "该用户已经抢购过该商品";
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
if(StringUtils.isEmpty(errMsg)){
return ResultBean.success();
}else{
return ResultBean.failure().msg(errMsg);
}
}
2.基于zookeeper实现分布式锁
zk分布式锁,就是某个节点尝试创建临时znode,此时创建成功了就获取了这个锁;这个时候别的客户端来创建锁会失败,只能注册个监听器监听这个锁。
释放锁就是删除这个znode,一旦释放掉就会通知客户端,然后有一个等待着的客户端就可以再次重新加锁。
以下代码经过封装,我们直接调用别人封装好的代码
<!-- zookeeper start -->
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.10</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
<exclusion>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>2.12.0</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>2.12.0</version>
</dependency>
package com.zl.shop.config;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.RetryNTimes;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ZooKeeperConfig {
/**
* 自定义注入ZooKeeper客户端操作实例
* @return
*/
@Bean
public CuratorFramework curatorFramework(){
CuratorFramework curatorFramework=CuratorFrameworkFactory.builder()
.connectString("127.0.0.1:2181")
.namespace("kill")
//重试策略
.retryPolicy(new RetryNTimes(5,1000))
.build();
curatorFramework.start();
return curatorFramework;
}
}
@Autowired
private CuratorFramework curatorFramework;
/**
* @description: 抢购-zookeeper分布式锁优化
* @author: zhanglei
* @createTime: 2021/10/28 15:14
**/
@Override
public ResultBean goodKill5(Integer goodId, Integer userId) {
String errMsg="";
InterProcessMutex mutex = new InterProcessMutex(curatorFramework,"/zkLock/"+userId+goodId+"-lock");
try {
if(mutex.acquire(10,TimeUnit.SECONDS)) {
//判断当前用户是否抢购过该商品
Integer count = killSuccessMapper.selectCount(new LambdaQueryWrapper<ItemKillSuccess>()
.eq(ItemKillSuccess::getUserId, userId).eq(ItemKillSuccess::getKillId, goodId));
if (count == 0) {
//校验库存
GoodVo goodVo = itemKillMapper.goodDetail(goodId);
if (goodVo != null && goodVo.getCanKill() == 1) {
//更新库存
int row = itemKillMapper.killOne(goodId);
if (row > 0) {
//更新成功,生成订单
generateOrder(goodVo, userId);
}
} else {
errMsg = "目前无法抢购";
}
} else {
errMsg = "该用户已经抢购过该商品";
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if(mutex != null){
try {
mutex.release();
} catch (Exception e) {
e.printStackTrace();
}
}
}
if(StringUtils.isEmpty(errMsg)){
return ResultBean.success();
}else{
return ResultBean.failure().msg(errMsg);
}
}