获取锁
互斥:确保只有一个线程获得锁
# 添加锁 利用setnx的互斥性
127.0.0.1:6379> setnx lock thread1
释放锁
手动释放锁
超时释放:获取锁时设置一个超时时间
#释放锁 删除即可
127.0.0.1:6379> del lock
两步合成一步
help set
SET key value [EX seconds] [PX milliseconds] [NX|XX]
summary: Set the string value of a key
since: 1.0.0
group: string
127.0.0.1:6379> get k1
(nil)
127.0.0.1:6379> set lock k1 ex 5 nx
OK
127.0.0.1:6379> set lock k1 ex 5 nx
nil
分布式锁解决方案_Redis实现的分布式锁
编写创建订单实现类
@Override
public String createOrderRedis(Integer productId, Integer count) throws Exception {
log.info("*************** 进入方法 **********");
String key = "lock:";
String value = UUID.randomUUID().toString();
// 获取分布式锁
Boolean result = stringRedisTemplate.opsForValue().setIfAbsent(key+productId, String.valueOf(Thread.currentThread().getId()),30,TimeUnit.SECONDS);
// 判断是否获取锁成功
if (!result){
log.info("我进入了锁");
return "不允许重复下单";
}
try {
// 1、根据商品id查询商品信息
Product product = productMapper.selectById(productId);
// 2、判断商品是否存在
if (product == null) {
throw new RuntimeException("购买商品不存在:" + productId + "不存在");
}
// 3、校验库存
if (count > product.getCount()) {
throw new RuntimeException("商品" + productId + "仅剩" + product.getCount() + "件,无法购买");
}
// 4、计算库存
Integer leftCount = product.getCount() - count;
// 5、更新库存
product.setCount(leftCount);
productMapper.updateById(product);
// 6、 创建订单
TOrder order = new TOrder();
order.setOrderStatus(1);//待处理
order.setReceiverName("张三");
order.setReceiverMobile("18587781068");
order.setOrderAmount(product.getPrice().multiply(new BigDecimal(count)));//订单价格
baseMapper.insert(order);
// 7、 创建订单和商品关系数据
OrderItem orderItem = new OrderItem();
orderItem.setOrderId(order.getId());
orderItem.setProduceId(product.getId());
orderItem.setPurchasePrice(product.getPrice());
orderItem.setPurchaseNum(count);
orderItemMapper.insert(orderItem);
return order.getId();
}catch (Exception e){
e.printStackTrace();
}finally {
// 释放锁
stringRedisTemplate.delete(key+productId);
}
return "创建失败";
}
Redis分布式锁误删除问题
Redis分布式锁误删除问题解决方案
设置超时时间远大于业务执行时间,但是会带来性能问题
删除锁的时候要判断,是不是自己的,如果是再删除
配置锁标识
private static final String KEY_PREFIX = "lock:";
private static final String ID_PREFIX = UUID.randomUUID().toString().replace("-","");
获取锁
//1、获取线程标识
String threadId = ID_PREFIX + Thread.currentThread().getId();
// 2、获得锁 setnx key value time type
Boolean result = stringRedisTemplate.opsForValue().setIfAbsent(KEY_PREFIX+produceId, threadId, 30, TimeUnit.SECONDS);
释放锁
// 获取锁标识
String s = stringRedisTemplate.opsForValue().get(KEY_PREFIX + produceId);
// 判断标识是否一致
if (s.equals(threadId)){
// 释放锁
stringRedisTemplate.delete(KEY_PREFIX + produceId);
}
Redis分布式锁不可重入问题
分布式锁解决方案_基于Redisson实现的分布式锁实现
Redisson介绍
Redisson - 是一个高级的分布式协调Redis客服端,能帮助用户在分布式环境中轻松实现一些Java的对象,Redisson、Jedis、Lettuce 是三个不同的操作 Redis 的客户端,Jedis、Lettuce 的 API 更侧重对 Reids 数据库的 CRUD(增删改查),而 Redisson API 侧重于分布式开发。
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>3.17.2</version>
</dependency>
编写Redis分布式锁工具类
package com.itbaizhan.lock.utils;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
@Component
@Slf4j
public class DistributedRedisLock {
@Autowired
private RedissonClient redissonClient;
// 加锁
public Boolean lock(String lockName) {
if (redissonClient == null) {
log.info("DistributedRedisLock redissonClient is null");
return false;
}
try {
RLock lock = redissonClient.getLock(lockName);
// 锁15秒后自动释放,防止死锁
lock.lock(15, TimeUnit.SECONDS);
log.info("Thread [{}] DistributedRedisLock lock [{}] success", Thread.currentThread().getName(), lockName);
// 加锁成功
return true;
} catch (Exception e) {
log.error("DistributedRedisLock lock [{}] Exception:", lockName, e);
return false;
}
}
// 释放锁
public Boolean unlock(String lockName) {
if (redissonClient == null) {
log.info("DistributedRedisLock redissonClient is null");
return false;
}
try {
RLock lock = redissonClient.getLock(lockName);
lock.unlock();
log.info("Thread [{}] DistributedRedisLock unlock [{}] success", Thread.currentThread().getName(), lockName);
// 释放锁成功
return true;
} catch (Exception e) {
log.error("DistributedRedisLock unlock [{}] Exception:", lockName, e);
return false;
}
}
}
编写创建订单接口实现
/**
* Redis锁实现
*
* @param productId
* @param count
* @return
* @throws Exception
*/
@Override
public String createOrderRedis(Integer productId, Integer count) throws Exception {
//获取锁对象
if (distributedRedisLock.lock(String.valueOf(productId))) {
try {
// 1、根据商品id查询商品信息
Product product = productMapper.selectById(productId);
// 2、判断商品是否存在
if (product == null) {
throw new RuntimeException("购买商品不存在:" + productId + "不存在");
}
// 3、校验库存
if (count > product.getCount()) {
throw new RuntimeException("商品" + productId + "仅剩" + product.getCount() + "件,无法购买");
}
// 4、计算库存
Integer leftCount = product.getCount() - count;
// 5、更新库存
product.setCount(leftCount);
productMapper.updateById(product);
// 6、 创建订单
TOrder order = new TOrder();
order.setOrderStatus(1);//待处理
order.setReceiverName("张三");
order.setReceiverMobile("18587781068");
order.setOrderAmount(product.getPrice().multiply(new BigDecimal(count)));//订单价格
baseMapper.insert(order);
// 7、 创建订单和商品关系数据
OrderItem orderItem = new OrderItem();
orderItem.setOrderId(order.getId());
orderItem.setProduceId(product.getId());
orderItem.setPurchasePrice(product.getPrice());
orderItem.setPurchaseNum(count);
orderItemMapper.insert(orderItem);
return order.getId();
} catch (Exception e) {
e.printStackTrace();
} finally {
distributedRedisLock.unlock(String.valueOf(productId));
}
}
return "创建失败";
}