获取锁
互斥:确保只有一个线程获得锁
# 添加锁 利用setnx的互斥性
127.0.0.1:6379> setnx lock thread1
释放锁
手动释放锁
超时释放:获取锁时设置一个超时时间
#释放锁 删除即可
127.0.0.1:6379> del lock
两步合成一步
help setSET key value [EX seconds] [PX milliseconds] [NX|XX]summary: Set the string value of a keysince: 1.0.0group: string127.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实现的分布式锁
编写创建订单实现类
@Overridepublic 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 typeBoolean 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 {@Autowiredprivate 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*/@Overridepublic 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 "创建失败";}