springboot 集成redission 以及分布式锁的使用详解

作者:介寒食 时间:2023-06-20 06:48:43 

springboot集成redission及分布式锁的使用

1、引入jar包


<dependency>
   <groupId>org.redisson</groupId>
   <artifactId>redisson</artifactId>
   <version>3.13.4</version>
</dependency>

2、增加Configuration类


@Configuration
public class RedissonConfig {
   @Value("${spring.redis.host}")
   private String host;

@Value("${spring.redis.port}")
   private String port;

@Value("${spring.redis.password}")
   private String password;

@Bean
   public RedissonClient getRedisson() {
       Config config = new Config();
       config.useSingleServer().setAddress("redis://" + host + ":" + port).setPassword(password);
       return Redisson.create(config);
   }
}

3、使用redission分布式锁


@Autowired
private RedissonClient redissonClient;

//方法区
String key = "aa:bb:cc:01";
RLock rLock =redissonClient.getLock(key);
try{<br>// 尝试加锁,最多等待1秒,上锁以后10秒自动解锁<br>// 没有Watch Dog ,10s后自动释放
boolean res = rLock.tryLock(1,10, TimeUnit.SECONDS);
if(!res){
return new GeneralVO<>(400, "请勿重复提交", false);
}
}finally{
   rLock.unlock();
}

private void redissonDoc() throws InterruptedException {
   //1. 普通的可重入锁
   RLock lock = redissonClient.getLock("generalLock");

// 拿锁失败时会不停的重试
   // 具有Watch Dog 自动延期机制 默认续30s 每隔30/3=10 秒续到30s
   lock.lock();

// 尝试拿锁10s后停止重试,返回false
   // 具有Watch Dog 自动延期机制 默认续30s
   boolean res1 = lock.tryLock(10, TimeUnit.SECONDS);

// 拿锁失败时会不停的重试
   // 没有Watch Dog ,10s后自动释放
   lock.lock(10, TimeUnit.SECONDS);

// 尝试拿锁100s后停止重试,返回false
   // 没有Watch Dog ,10s后自动释放
   boolean res2 = lock.tryLock(100, 10, TimeUnit.SECONDS);

//2. 公平锁 保证 Redisson 客户端线程将以其请求的顺序获得锁
   RLock fairLock = redissonClient.getFairLock("fairLock");

//3. 读写锁 没错与JDK中ReentrantLock的读写锁效果一样
   RReadWriteLock readWriteLock = redissonClient.getReadWriteLock("readWriteLock");
   readWriteLock.readLock().lock();
   readWriteLock.writeLock().lock();
}

Springboot整合Redisson 锁

Redisson是一个在Redis的基础上实现的Java驻内存数据网格

一、依赖


 <dependency>
     <groupId>org.redisson</groupId>
     <artifactId>redisson</artifactId>
     <version>3.15.4</version>
 </dependency>

二、配置文件


spring:
 redis:
   database: 7
   host: 116.62.178.11
   port: 6379
   password: 1234qwer
   #  spring-boot 1.0默认 jedis;  spring-boot2.0 默认lettuce ,lettuce线程安全
   lettuce:
     pool:
       # 连接池中的最大空闲连接 默认8
       max-idle: 8
       # 连接池中的最小空闲连接 默认0
       min-idle: 500
       # 连接池最大连接数 默认8 ,负数表示没有限制
       max-active: 2000
       # 连接池最大阻塞等待时间(使用负值表示没有限制) 默认-1
       max-wait: -1
   cache:
     type: redis

@Configuration
public class RedissonConfig {
   @Value("${spring.redis.host}")
   private String host;
   @Value("${spring.redis.port}")
   private int port;
   @Value("${spring.redis.password}")
   private String password;
   @Bean(destroyMethod = "shutdown")
   RedissonClient redissonClient() throws IOException {
       Config config = new Config();
       config.useSingleServer()
               .setPassword(password)
               .setAddress("redis://" + host + ":" + port).setDatabase(7);
       return Redisson.create(config);
   }
}

三、锁的使用

读写锁


public class RedissionDemo {
   @Autowired
   private RedissonClient redissonClient;
   @Autowired
   private RedisTemplate redisTemplate;
   /**
    * 读写锁 总结
    *
    * 读锁又叫共享锁
    * 写锁又叫排他锁(互斥锁)
    * 读 + 读 相当于无锁,并发读,同时加锁成功
    * 写 + 写 阻塞状态
    * 写 + 读 等待写锁释放
    * 读 + 写 等待读锁完,才写,
    */
   public String writeValue() {
       String str = "";
       RReadWriteLock readWriteLock = redissonClient.getReadWriteLock("writeLock");
       RLock rLock = readWriteLock.writeLock();
       try {
           rLock.lock();
           str = UUID.randomUUID().toString();
           redisTemplate.opsForValue().set("uuid", str);
           Thread.sleep(30000);
       } catch (Exception e) {
       } finally {
           rLock.unlock();
       }
       return str;
   }
   /**
    * 读锁
    *
    * @return
    */
   public String readValue() {
       String str = "";
       RReadWriteLock readWriteLock = redissonClient.getReadWriteLock("writeLock");
       RLock rLock = readWriteLock.readLock();
       rLock.lock();
       str = (String) redisTemplate.opsForValue().get("uuid");
       rLock.unlock();
       return str;
   }

}

信号量


public class RedissionDemo {
   @Autowired
   private RedissonClient redissonClient;
   @Autowired
   private RedisTemplate redisTemplate;
   /**
    * 信号量
    *
    * @return
    */
   //停车方法
   @GetMapping("/park")
   public String park() throws InterruptedException {
       //这里是获取信号量的值,这个信号量的name一定要与你初始化的一致
       RSemaphore park = redissonClient.getSemaphore("park");
       //这里会将信号量里面的值-1,如果为0则一直等待,直到信号量>0
       park.acquire();
       //tryAcquire为非阻塞式等待
       //park.tryAcquire();
       return "ok";
   }
   public String go() throws InterruptedException {
       //这里是获取信号量的值,这个信号量的name一定要与你初始化的一致
       RSemaphore park = redissonClient.getSemaphore("park");
       //这里会将信号量里面的值+1,也就是释放信号量
       park.release();
       return "ok";
   }
}

闭锁


public class RedissionDemo {
   @Autowired
   private RedissonClient redissonClient;
   @Autowired
   private RedisTemplate redisTemplate;

/**
    * 闭锁,限流
    *
    * @return
    * @throws InterruptedException
    */
   //锁门
   public String lockdoor() throws InterruptedException {
       RCountDownLatch door = redissonClient.getCountDownLatch("door");
       //设置一个班级有20个同学
       door.trySetCount(20);
       //需要等到20个同学全部离开,才锁门
       door.await();
       return "锁门了";
   }
   public String leave(Long id) throws InterruptedException {
       RCountDownLatch door = redissonClient.getCountDownLatch("door");
       //表示一个同学离开
       door.countDown();
       return "" + id + "号同学离开了";
   }
}

四、分布式秒杀

springboot 集成redission 以及分布式锁的使用详解 springboot 集成redission 以及分布式锁的使用详解

秒杀流程:

springboot 集成redission 以及分布式锁的使用详解


@Service
@Slf4j
public class DistributedSecKillBiz {
   @Autowired
   private RedisTemplate redisTemplate;
   @Autowired
   private RedissonClient redissonClient;

/**
    * 分布式锁。唯一缺点 枷锁失效时间
    * 枷锁院子操作,
    * 解锁,删除锁也是原子操作 瑕疵没有续命
    *
    * @return
    */
   public String doKill() {
       String lock = UUID.randomUUID().toString();
       String goodsId = "10054";
       boolean flag = redisTemplate.opsForValue().setIfAbsent(goodsId, lock, 30, TimeUnit.SECONDS);
       if (flag) {
           // 获取锁成功
           try {
               Long stock = redisTemplate.opsForValue().decrement(upActivityKey() + SecKillConstant.CACHE_FOODS_COUNT + goodsId);
               if (stock > 0) {
                   redisTemplate.opsForValue().increment(upActivityKey() + SecKillConstant.CACHE_FOODS_COUNT + goodsId);
                   log.info("扣减库存成功,还剩:" + stock);
               }
               return "库存不足,该商品已抢购完!";
           } catch (Exception e) {
           } finally {
               String script = "if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";
               redisTemplate.execute(new DefaultRedisScript<>(script, Long.class), Arrays.asList(goodsId), lock);
           }
       }
       return doKill();
   }
   /**
    * 整合 redission
    * @return
    */
   public String doKillDistributed() {
       String goodsId = "10054";
       RLock lock = redissonClient.getLock(upActivityKey() + SecKillConstant.LOCK + goodsId);
       // 获取锁成功
       try {
           //1 阻塞式等待,默认30秒时间
           //2 自动续期,如果业务超长,续上新的30秒,不用担心过期时间,锁自动删除掉
           //3 枷锁的业务运行完成,就不会给当前的锁自动续期,即使没有手动释放锁也会,30秒自动释放
//            lock.lock(30, TimeUnit.SECONDS); //不会自动续期需要注意
           lock.lock();
           Long stock = redisTemplate.opsForValue().decrement(upActivityKey() + SecKillConstant.CACHE_FOODS_COUNT + goodsId);
           if (stock > 0) {
               redisTemplate.opsForValue().increment(upActivityKey() + SecKillConstant.CACHE_FOODS_COUNT + goodsId);
               log.info("扣减库存成功,还剩:" + stock);
           }
           return "库存不足,该商品已抢购完!";
       } catch (Exception e) {
       } finally {
           lock.unlock();
       }
       return "fail";
   }
   /**
    * 获取活动
    *
    * @return
    */
   public ActivityBo upActivity() {
       return new ActivityBo("七夕活动", "SEVEN_ACTIVITY", new Date(), new Date());
   }
   /**
    * 活动公共key
    *
    * @return
    */
   public String upActivityKey() {
       return SecKillConstant.SEC_KILL + upActivity().getActivityKey() + ":";
   }
}

五、redis锁 单机版可用,分布式用Redisson


package com.yang.yimall.seckill.app.seckill.biz;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import java.util.Collections;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
/**
* redis 锁 集群有瑕疵 不能 续命
*/
@Service
public class RedisLock {
   @Autowired
   private RedisTemplate redisTemplate;
   private String lockName = "lockName";
   private ThreadLocal<String> threadLocal = new ThreadLocal<>();
   public void lock(String lockName) {
       if (tryLock(lockName)) {
           return;
       }
       lock(lockName);
   }
   public void lock() {
       if (tryLock(lockName)) {
           return;
       }
       lock();
   }
   /**
    * 添加key 并且设置过期时间 原子操作
    *
    * @param lockName
    * @return
    */
   public boolean tryLock(String lockName) {
       String uuid = UUID.randomUUID().toString();
       threadLocal.set(uuid);
       return redisTemplate.opsForValue().setIfAbsent(lockName, uuid, 30, TimeUnit.SECONDS);
   }
   /**
    * 如果查询有key,就删除, 原子操作
    */
   public void unlock() {
       String script = "if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";
       redisTemplate.execute(new DefaultRedisScript<Long>(script, Long.class), Collections.singletonList(lockName), threadLocal.get());
   }
}

使用


public String doKillUp() {
       String goodsId = "10054";
       redisLock.lock(goodsId);
       // 获取锁成功
       try {
           Long stock = redisTemplate.opsForValue().decrement(upActivityKey() + SecKillConstant.CACHE_FOODS_COUNT + goodsId);
           if (stock > 0) {
               redisTemplate.opsForValue().increment(upActivityKey() + SecKillConstant.CACHE_FOODS_COUNT + goodsId);
               log.info("扣减库存成功,还剩:" + stock);
           }
           return "库存不足,该商品已抢购完!";
       } catch (Exception e) {
       } finally {
           redisLock.unlock();
       }
       return "库存不足,该商品已抢购完!";
   }

springboot 集成redission 以及分布式锁的使用详解

来源:https://www.cnblogs.com/jiehanshi/p/13693129.html

标签:springboot,redission,分布式锁
0
投稿

猜你喜欢

  • 一文助你搞懂参数传递原理解析(java、go、python、c++)

    2022-04-04 13:10:15
  • MyBatis-Plus实现字段自动填充功能的示例

    2022-03-06 21:48:29
  • Android实现中国象棋附源码下载

    2023-12-20 17:09:10
  • IDEA不编译除了.java之外的文件的解决办法(推荐)

    2023-09-16 15:50:44
  • Android笔记之:CM9源码下载与编译的应用

    2022-09-23 05:40:14
  • JavaWeb实现注册用户名检测

    2022-07-20 05:25:46
  • Android UI控件之Gallery实现拖动式图片浏览效果

    2023-02-06 13:22:01
  • 简单实现Java web服务器

    2023-10-11 16:47:13
  • Android显示系统SurfaceFlinger详解

    2022-11-02 12:39:53
  • springboot vue组件开发实现接口断言功能

    2023-11-12 10:26:53
  •  Java SE 面向对象编程的3个常用接口

    2023-01-14 06:42:32
  • Java中一个for语句导致无穷大死循环的例子

    2022-12-17 08:13:33
  • c语言实现的几种常用排序算法

    2022-02-23 04:04:11
  • C#使用timer实现的简单闹钟程序

    2023-07-30 00:24:28
  • Java中Range函数的简单介绍

    2023-10-18 05:33:35
  • mybatis中的if test判断入参的值问题

    2023-11-16 08:13:44
  • 实例分析java开启线程的方法

    2022-06-24 19:54:00
  • SpringBoot资源文件的存放位置设置方式

    2023-02-26 10:37:00
  • 详解Java 信号量Semaphore

    2021-12-22 11:10:36
  • Java 如何实现时间控制

    2023-02-20 06:19:23
  • asp之家 软件编程 m.aspxhome.com