文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

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

2024-04-02 19:55

关注

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;
    }
    
    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;
    
    //停车方法
    @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;
 
    
    //锁门
    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 + "号同学离开了";
    }
}

四、分布式秒杀

在这里插入图片描述 在这里插入图片描述

秒杀流程:

在这里插入图片描述


@Service
@Slf4j
public class DistributedSecKillBiz {
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private RedissonClient redissonClient;
 
    
    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();
    }
    
    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";
    }
    
    public ActivityBo upActivity() {
        return new ActivityBo("七夕活动", "SEVEN_ACTIVITY", new Date(), new Date());
    }
    
    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;

@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();
    }
    
    public boolean tryLock(String lockName) {
        String uuid = UUID.randomUUID().toString();
        threadLocal.set(uuid);
        return redisTemplate.opsForValue().setIfAbsent(lockName, uuid, 30, TimeUnit.SECONDS);
    }
    
    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 "库存不足,该商品已抢购完!";
    }

在这里插入图片描述

以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程网。

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     807人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     351人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     314人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     433人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     221人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯