赞
踩
基于setnx实现的分布式锁存在下面的问题:
重入问题:重入问题是指 获得锁的线程可以再次进入到相同的锁的代码块中,可重入锁的意义在于防止死锁,比如HashTable这样的代码中,他的方法都是使用synchronized修饰的,假如他在一个方法内,调用另一个方法,那么此时如果是不可重入的,不就死锁了吗?所以可重入锁他的主要意义是防止死锁,我们的synchronized和Lock锁都是可重入的。
不可重试:是指目前的分布式只能尝试一次,我们认为合理的情况是:当线程在获得锁失败后,他应该能再次尝试获得锁。
超时释放:我们在加锁时增加了过期时间,这样的我们可以防止死锁,但是如果卡顿的时间超长,虽然我们采用了lua表达式防止删锁的时候,误删别人的锁,但是毕竟没有锁住,有安全隐患
主从一致性: 如果Redis提供了主从集群,当我们向集群写数据时,主机需要异步的将数据同步给从机,而万一在同步过去之前,主机宕机了,就会出现死锁问题。
那么什么是Redission呢
Redisson是一个在Redis的基础上实现的Java驻内存数据网格(In-Memory Data Grid)。它不仅提供了一系列的分布式的Java常用对象,还提供了许多分布式服务,其中就包含了各种分布式锁的实现。
Redission提供了分布式锁的多种多样的功能
官网地址:Redisson: Easy Redis Java client with features of In-Memory Data Grid
GitHub地址: https://github.com/redisson/redisson
引入依赖:
- <dependency>
- <groupId>org.redisson</groupId>
- <artifactId>redisson</artifactId>
- <version>3.13.6</version>
- </dependency>
配置Redisson客户端:
- @Configuration
- public class RedissonConfig {
-
- @Bean
- public RedissonClient redissonClient(){
- // 配置
- Config config = new Config();
- config.useSingleServer().setAddress("redis://192.168.150.101:6379")
- .setPassword("123321");
- // 创建RedissonClient对象
- return Redisson.create(config);
- }
- }
如何使用Redission的分布式锁
- @Resource
- private RedissionClient redissonClient;
-
- @Test
- void testRedisson() throws Exception{
- //获取锁(可重入),指定锁的名称
- RLock lock = redissonClient.getLock("anyLock");
- //尝试获取锁,参数分别是:获取锁的最大等待时间(期间会重试),锁自动释放时间,时间单位
- boolean isLock = lock.tryLock(1,10,TimeUnit.SECONDS);
- //判断获取锁成功
- if(isLock){
- try{
- System.out.println("执行业务");
- }finally{
- //释放锁
- lock.unlock();
- }
-
- }
-
-
-
- }
在 VoucherOrderServiceImpl
注入RedissonClient
- @Resource
- private RedissonClient redissonClient;
-
- @Override
- public Result seckillVoucher(Long voucherId) {
- // 1.查询优惠券
- SeckillVoucher voucher = seckillVoucherService.getById(voucherId);
- // 2.判断秒杀是否开始
- if (voucher.getBeginTime().isAfter(LocalDateTime.now())) {
- // 尚未开始
- return Result.fail("秒杀尚未开始!");
- }
- // 3.判断秒杀是否已经结束
- if (voucher.getEndTime().isBefore(LocalDateTime.now())) {
- // 尚未开始
- return Result.fail("秒杀已经结束!");
- }
- // 4.判断库存是否充足
- if (voucher.getStock() < 1) {
- // 库存不足
- return Result.fail("库存不足!");
- }
- Long userId = UserHolder.getUser().getId();
- //创建锁对象 这个代码不用了,因为我们现在要使用分布式锁
- //SimpleRedisLock lock = new SimpleRedisLock("order:" + userId, stringRedisTemplate);
- RLock lock = redissonClient.getLock("lock:order:" + userId);
- //获取锁对象
- boolean isLock = lock.tryLock();
-
- //加锁失败
- if (!isLock) {
- return Result.fail("不允许重复下单");
- }
- try {
- //获取代理对象(事务)
- IVoucherOrderService proxy = (IVoucherOrderService) AopContext.currentProxy();
- return proxy.createVoucherOrder(voucherId);
- } finally {
- //释放锁
- lock.unlock();
- }
- }
Redisson分布式锁快速入门步骤1:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。