基于 Redis 实现的分布式锁

获取锁

互斥:确保只有一个线程获得锁

# 添加锁 利用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 "创建失败";
   }

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值