软件编程
位置:首页>> 软件编程>> java编程>> springboot 集成redission 以及分布式锁的使用详解

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

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

标签:springboot,redission,分布式锁

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

0
投稿

猜你喜欢

手机版 软件编程 asp之家 www.aspxhome.com