springBoot整合redission框架

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 Tair(兼容Redis),内存型 2GB
简介: springBoot整合redission框架

# springBoot整合redission框架

pom依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson-spring-boot-starter</artifactId>
            <version>3.12.5</version>
        </dependency>
        <!--整合redission框架enc-->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
        </dependency>

YML配置

spring:
  #redisson配置,默认连接库0,无密码只配置连接地址即可
  redis:
    host: 127.0.0.1
    database: 0
    password:

redission锁使用

package com.cyc.redission.n1;

import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import java.util.Calendar;
import java.util.concurrent.TimeUnit;

@RestController
@RequestMapping("/lock")
public class RedissonLockTest {

    public static int amount = 5;

    @Autowired
    private RedissonClient redissonClient;

    //没获取到锁阻塞线程
    @RequestMapping(value = "/test", method = RequestMethod.GET)
    public Integer test() {
        RLock lock = null;
        try {
            //TODO 创建一个名字为lock的锁,如果是并发访问,会阻塞到 lock.lock();,知道2秒后,才能执行下面的逻辑代码
            lock = redissonClient.getLock("lock");
            lock.lock();
            System.out.println(formatDate() + " " + Thread.currentThread().getName() + "获取到锁");
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            if (null != lock && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
        return amount;
    }

    //立刻返回获取锁的状态
    @RequestMapping("/test1")
    public Integer test1() {
        RLock lock = null;
        try {
            lock = redissonClient.getLock("lock");
            //TODO 判断获取锁,执行业务逻辑,否则直接返回提示信息
            if (lock.tryLock()) {
                System.out.println(formatDate() + " " + Thread.currentThread().getName() + "获取到锁");
                Thread.sleep(2000);
            } else {
                System.out.println(formatDate() + " " + Thread.currentThread().getName() + "已抢光");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            if (null != lock && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
        return amount;
    }

    //立刻返回获取锁的状态
    @RequestMapping("/test2")
    public Integer test2() {
        RLock lock = redissonClient.getLock("lock"); //非公平锁,随机取一个等待中的线程分配锁
        //RLock lock=redissonClient.getFairLock("lock"); //公平锁,按照先后顺序依次分配锁
        try {
            if (lock.tryLock(2, 10, TimeUnit.SECONDS)) { //最多等待锁2秒,10秒后强制解锁,推荐使用
                System.out.println(formatDate() + " " + Thread.currentThread().getName() + "获取到锁");
                Thread.sleep(4500);
            } else {
                System.out.println(formatDate() + " " + Thread.currentThread().getName() + "未获取到锁");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            if (null != lock && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
        return amount;
    }

    public String formatDate() {
        Calendar c = Calendar.getInstance();
        return c.get(Calendar.SECOND) + ":" + c.get(Calendar.MILLISECOND);
    }
}

限流器

package com.cyc.redission.n1;

import org.redisson.api.RRateLimiter;
import org.redisson.api.RateIntervalUnit;
import org.redisson.api.RateType;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/*
 * 限流器
 * 1.先调用init方法生成5个令牌
 * 2.通过该限流器的名称rateLimiter来获取令牌limiter.tryAcquire()
 * 3.谁抢到,谁先执行,否则返回提示信息,可以用于秒杀场景
 * */
@RestController
@RequestMapping("/limiter")
public class RateLimiterTest {

    @Autowired
    private RedissonClient redissonClient;

    //初始化限流器
    @RequestMapping("/init")
    public void init() {
        RRateLimiter limiter = redissonClient.getRateLimiter("rateLimiter");
        limiter.trySetRate(RateType.PER_CLIENT, 5, 1, RateIntervalUnit.SECONDS);//每1秒产生5个令牌
    }

    //获取令牌
    @RequestMapping("/thread")
    public void thread() {
        RRateLimiter limiter = redissonClient.getRateLimiter("rateLimiter");
        if (limiter.tryAcquire()) {//尝试获取1个令牌
            System.out.println(Thread.currentThread().getName() + "成功获取到令牌");
        } else {
            System.out.println(Thread.currentThread().getName() + "未获取到令牌");
        }
    }
}

List、Queue测试

package com.cyc.redission.n1;

import org.redisson.api.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.PostConstruct;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;

//List、Queue测试
@RestController
@RequestMapping("/collection")
public class RedisQueueTest {

    @Autowired
    private RedissonClient redissonClient;


    /**
     * //List测试 - 添加元素
     * http://127.0.0.1:8080/collection//list/add?a="亚春2"
     * http://127.0.0.1:8080/collection//list/add?a="亚春2"
     * 1. 可添加相同名称的元素
     *
     * @param a
     * @return
     */
    @RequestMapping("/list/add")
    public List<String> addAndGetList(String a) {
        RList<String> list = redissonClient.getList("my_list");
        list.add(a);
        return list.readAll();
    }


    /**
     * //List测试 - 删除元素
     * http://127.0.0.1:8080/collection//list/del?a="亚春2"
     * 1 removeAll():删除值相同的多个元素
     * 2 remove()删除元素,仅删除匹配到的第一个元素
     *
     * @param a
     * @return
     */
    @RequestMapping("/list/del")
    public List<String> removeList(String a) {
        RList<String> list = redissonClient.getList("my_list");
      /* 自定义删除条件
      list.removeIf(new Predicate<String>() {
          @Override
          public boolean test(String s) {
              return s.length()>10;
          }
      });*/

        //list.remove(a);//删除元素,仅删除匹配到的第一个元素
        list.removeAll(Arrays.asList(a));//删除指定集合中所有元素
        return list.readAll();
    }

    //Queue测试 - 添加元素
    @RequestMapping("/queue/add")
    public List<String> addQueue(String a) {
        RQueue<String> list = redissonClient.getQueue("my_queue");
        list.add(a);//添加一个元素到集合最末尾
        return list.readAll();
    }

    //Queue测试 - 读取元素
    @RequestMapping("/queue/poll")
    public String pollQueue() {
        RQueue<String> list = redissonClient.getQueue("my_queue");
        return list.poll();//从队列的头部获取一个元素并从队列中删除该元素,队列为空时返回null
    }

    //Blocking Queue测试 - 添加元素
    @RequestMapping("/blocking/add")
    public List<String> addBlockingQueue(String a) {
        RBlockingQueue<String> list = redissonClient.getBlockingQueue("my_blocking_queue");
        list.add(a);
        return list.readAll();
    }

    //Blocking Queue测试 - 读取元素
    @RequestMapping("/blocking/get")
    public String getBlockingQueue() throws InterruptedException {
        RBlockingQueue<String> list = redissonClient.getBlockingQueue("my_blocking_queue");
        //return list.poll();//从队列的头部获取一个元素并从队列中删除该元素,队列为空时返回null
        return list.take();//从队列的头部获取一个元素并从队列中删除该元素,队列为空时阻塞线程
        //return list.peek();//从队列的头部获取一个元素但不删除该元素,队列为空时返回null
    }

    //Delayed Queue测试 - 添加元素
    @RequestMapping("/delayed/add")
    public List<String> addDelayedQueue(String a, Long b) {
        RQueue<String> queue = redissonClient.getQueue("my_blocking_queue");//目标队列
        RDelayedQueue<String> list = redissonClient.getDelayedQueue(queue);//延迟队列,数据临时存放地,发出后删除该元素
        list.offer(a, b, TimeUnit.SECONDS);
        return list.readAll();
    }

    @PostConstruct
    public void acceptElement() {
        RBlockingQueue<String> list = redissonClient.getBlockingQueue("my_blocking_queue");
        list.subscribeOnElements(new Consumer<String>() {
            public void accept(String s) {
                System.out.println("获取到元素:" + s);
            }
        });
    }
}

RedisRScoredSortedSet

package com.cyc.redission.n1;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.DateUtils;
import org.redisson.api.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Date;
import java.util.concurrent.TimeUnit;

@Slf4j
@RestController
@RequestMapping("/score")
public class RedisRScoredSortedSet {

    @Autowired
    private RedissonClient redissonClient;

    @RequestMapping("/add")
    public String addScore(String a,Double b){
        //创建Set
        RScoredSortedSet<String> set = redissonClient.getScoredSortedSet("simpleSet1");
        //设置过期时间
        boolean exists=set.isExists();
        set.addListener(new ExpiredObjectListener() {
            public void onExpired(String name) {
                System.out.println("超时事件被触发,name="+name);
                log.info("超时事件被触发,name={}",name);
            }
        });
        //添加元素
        set.addScore(a,b);
        if(!exists) {
            set.expireAt(DateUtils.addMinutes(new Date(), 2));
        }
        //获取元素在集合中的位置
        Integer index=set.revRank(a);
        //获取元素的评分
        Double score=set.getScore(a);
        log.info("size={},a={},index={},score={}",set.size(),a,index,score);

        //可以设置单一元属过期,但是不能触发对应过期事件
        RSetCache<String> map = redissonClient.getSetCache("simpleSet2");
        map.add(a,1, TimeUnit.MINUTES);
        //TODO 可设置,但不会触发监听.
        map.addListener(new ExpiredObjectListener() {
            public void onExpired(String name) {
                log.info("entryExpiredListener超时事件被触发,event={}",name);
            }
        });

        //不能设置单一元属过期
        RSet<String> set1 = redissonClient.getSet("simpleSet3");
        set1.add(a);

        return "SUCCESS";
    }

    @RequestMapping("/show")
    public String showList(String key){
        log.info("排行榜={}", key);
        RScoredSortedSet<String> set = redissonClient.getScoredSortedSet(key);
        set.stream().forEach(a->{
            Integer index=set.revRank(a);//获取元素在集合中的位置
            Double score=set.getScore(a);//获取元素的评分
            log.info("size={},key={},index={},score={}", set.size(), a, index, score);
        });
        return "SUCCESS";
    }

    @RequestMapping("/clear")
    public String clearList(){
        long size=redissonClient.getKeys().deleteByPattern("*impl*");
        log.info("删除数量:{}",size);
        return "SUCCESS";
    }

    @RequestMapping("/deleteAll")
    public String deleteAll(String pattern){
        long amount=redissonClient.getKeys().deleteByPattern(pattern);
        log.info("删除数量:{}",amount);
        return "SUCCESS";
    }
}

RedissonMapTest

package com.cyc.redission.n1;

import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RMapCache;
import org.redisson.api.RedissonClient;
import org.redisson.api.map.event.EntryEvent;
import org.redisson.api.map.event.EntryExpiredListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.PostConstruct;
import java.util.concurrent.TimeUnit;

@Slf4j
@RestController
@RequestMapping("/map")
public class RedissonMapTest {

    @Autowired
    private RedissonClient redissonClient;
    //测试map集合的名称
    private final static String key = "my_test_map";


    /**
     * //初始化Listener,仅初始化一次,过期事件不一定那么及时触发,存在一定的延时
     * //注意如果触发2次,则会执行2次回调..
     */
    @PostConstruct
    public void init() {
        //redissonClient.getXXX来创建不同类型的map ,KEY为要执行监听的key
        RMapCache<String, String> map = redissonClient.getMapCache(key);
        map.addListener(new EntryExpiredListener<String, String>() {
            @Override
            public void onExpired(EntryEvent<String, String> event) {
                log.info("{}已过期,原来的值为:{},现在的值为:{}", event.getKey(), event.getOldValue(), event.getValue());
            }
        });
        log.info("{}初始化完成", key);
    }

    //存放Key-Value对
    //http://127.0.0.1:8080/map/put/?a=myKey&b=myKeyValue22&flag=true
    @RequestMapping("/put")
    public String put(String a, String b, boolean flag) {
        //redissonClient.getXXX来创建不同类型的map ,KEY为要执行监听的key
        RMapCache<String, String> map = redissonClient.getMapCache(key);
        if (flag) {
            map.put(a, b, 2, TimeUnit.SECONDS);//key设置有效时间,并在实现时,触发上面的监听函数
        } else {
            map.put(a, b);
        }
        log.info("设置{}={}成功", a, b);
        return "SUCCESS";
    }

    /**
     * 遍历map中的所以元素,需要指定key
     *
     * @return
     */
    @RequestMapping("/show")
    public String put() {
        RMapCache<String, String> map = redissonClient.getMapCache(key);
        map.keySet().stream().forEach(i -> log.info("{},{}", i, map.get(i)));
        return "SUCCESS";
    }
}

RedisTopicTest

package com.cyc.redission.n1;

import org.redisson.api.RTopic;
import org.redisson.api.RedissonClient;
import org.redisson.api.listener.MessageListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.PostConstruct;

/*
 * 话题(订阅分发)
 * */
@RestController
@RequestMapping("/topic")
public class RedisTopicTest {

    @Autowired
    private RedissonClient redissonClient;


    /**
     * //分发
     * http://127.0.0.1:8080/topic/produce?a=redis主题
     *
     * @param a
     * @return
     */
    @RequestMapping("/produce")
    public String produce(String a) {
        RTopic topic = redissonClient.getTopic("anyTopic");
        topic.publish(a);
        return "发送消息:" + a;
    }

    //订阅
    @PostConstruct
    public void consume() {
        RTopic topic = redissonClient.getTopic("anyTopic");//订阅指定话题
        //RPatternTopic topic=redissonClient.getPatternTopic("*any*");//指定话题表达式订阅多个话题
        topic.addListener(String.class, new MessageListener<String>() {
            @Override
            public void onMessage(CharSequence charSequence, String map) {
                System.out.println("接收到消息:" + map);
            }
        });
    }
}

RedisTransactionTest

package com.cyc.redission.n1;

import org.apache.commons.lang3.RandomUtils;
import org.redisson.api.RMap;
import org.redisson.api.RTransaction;
import org.redisson.api.RedissonClient;
import org.redisson.api.TransactionOptions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.TimeUnit;

/*
* Redisson为RMap、RMapCache、RLocalCachedMap、RSet、RSetCache和RBucket这样的对象提供了具有ACID属性的事务功能
* Redisson事务通过分布式锁保证了连续写入的原子性,同时在内部通过操作指令队列实现了Redis原本没有的提交与滚回功能
* 当提交与滚回遇到问题的时候,将通过org.redisson.transaction.TransactionException告知用户
* */
@RestController
@RequestMapping("/tx")
public class RedisTransactionTest {

    @Autowired
    private RedissonClient redissonClient;

    @RequestMapping("/test/{key}")
    public void test(@PathVariable String key){
        TransactionOptions options=TransactionOptions.defaults().syncSlavesTimeout(5, TimeUnit.SECONDS)
                .responseTimeout(3,TimeUnit.SECONDS).retryInterval(2,TimeUnit.SECONDS)
                .retryAttempts(3).timeout(5,TimeUnit.SECONDS);
        RTransaction transaction=redissonClient.createTransaction(options);
        RMap<String, Integer> map=transaction.getMap("myMap");
        System.out.println(map.get("userId"));
        map.put("userId", RandomUtils.nextInt(1,100));
        System.out.println(map.get(key).toString());
        try {
            transaction.commit();
        } catch (Exception e) {
            e.printStackTrace();
            transaction.rollback();
        }
    }
}

CountDownLatchTest

package com.cyc.redission.n1;

import org.redisson.api.RCountDownLatch;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.TimeUnit;

@RestController
@RequestMapping("/count")
public class CountDownLatchTest {

    @Autowired
    private RedissonClient redissonClient;

    //主线程等待所有子线程完成
    @RequestMapping("/await")
    public void await(){
        try {
            RCountDownLatch latch = redissonClient.getCountDownLatch("latch");
            latch.trySetCount(3);//设置计数器初始大小
            long count = latch.getCount();
            System.out.println("count = " + count);
            latch.await();//阻塞线程直到计数器归零
            System.out.println(Thread.currentThread().getName()+"所有子线程已运行完毕");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    //子线程
    @RequestMapping("/thread")
    public void thread(){
        try {
            RCountDownLatch latch = redissonClient.getCountDownLatch("latch");
            System.out.println(Thread.currentThread().getName()+"抵达现场");
            TimeUnit.SECONDS.sleep(1);
            latch.countDown();//计数器减1,当计数器归零后通知所有等待着的线程恢复执行
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
21天前
|
XML 安全 Java
|
24天前
|
缓存 NoSQL Java
什么是缓存?如何在 Spring Boot 中使用缓存框架
什么是缓存?如何在 Spring Boot 中使用缓存框架
33 0
|
1月前
|
数据采集 监控 前端开发
二级公立医院绩效考核系统源码,B/S架构,前后端分别基于Spring Boot和Avue框架
医院绩效管理系统通过与HIS系统的无缝对接,实现数据网络化采集、评价结果透明化管理及奖金分配自动化生成。系统涵盖科室和个人绩效考核、医疗质量考核、数据采集、绩效工资核算、收支核算、工作量统计、单项奖惩等功能,提升绩效评估的全面性、准确性和公正性。技术栈采用B/S架构,前后端分别基于Spring Boot和Avue框架。
|
2月前
|
Java API 数据库
构建RESTful API已经成为现代Web开发的标准做法之一。Spring Boot框架因其简洁的配置、快速的启动特性及丰富的功能集而备受开发者青睐。
【10月更文挑战第11天】本文介绍如何使用Spring Boot构建在线图书管理系统的RESTful API。通过创建Spring Boot项目,定义`Book`实体类、`BookRepository`接口和`BookService`服务类,最后实现`BookController`控制器来处理HTTP请求,展示了从基础环境搭建到API测试的完整过程。
59 4
|
2月前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 实现动态路由和菜单功能,快速搭建前后端分离的应用框架
本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 实现动态路由和菜单功能,快速搭建前后端分离的应用框架。首先,确保开发环境已安装必要的工具,然后创建并配置 Spring Boot 项目,包括添加依赖和配置 Spring Security。接着,创建后端 API 和前端项目,配置动态路由和菜单。最后,运行项目并分享实践心得,包括版本兼容性、安全性、性能调优等方面。
178 1
|
2月前
|
Java API 数据库
Spring Boot框架因其简洁的配置、快速的启动特性及丰富的功能集而备受开发者青睐
本文通过在线图书管理系统案例,详细介绍如何使用Spring Boot构建RESTful API。从项目基础环境搭建、实体类与数据访问层定义,到业务逻辑实现和控制器编写,逐步展示了Spring Boot的简洁配置和强大功能。最后,通过Postman测试API,并介绍了如何添加安全性和异常处理,确保API的稳定性和安全性。
45 0
|
6天前
|
IDE Java 测试技术
互联网应用主流框架整合之Spring Boot开发
通过本文的介绍,我们详细探讨了Spring Boot开发的核心概念和实践方法,包括项目结构、数据访问层、服务层、控制层、配置管理、单元测试以及部署与运行。Spring Boot通过简化配置和强大的生态系统,使得互联网应用的开发更加高效和可靠。希望本文能够帮助开发者快速掌握Spring Boot,并在实际项目中灵活应用。
24 5
|
17天前
|
缓存 Java 数据库连接
Spring框架中的事件机制:深入理解与实践
Spring框架是一个广泛使用的Java企业级应用框架,提供了依赖注入、面向切面编程(AOP)、事务管理、Web应用程序开发等一系列功能。在Spring框架中,事件机制是一种重要的通信方式,它允许不同组件之间进行松耦合的通信,提高了应用程序的可维护性和可扩展性。本文将深入探讨Spring框架中的事件机制,包括不同类型的事件、底层原理、应用实践以及优缺点。
47 8
|
27天前
|
存储 Java 关系型数据库
在Spring Boot中整合Seata框架实现分布式事务
可以在 Spring Boot 中成功整合 Seata 框架,实现分布式事务的管理和处理。在实际应用中,还需要根据具体的业务需求和技术架构进行进一步的优化和调整。同时,要注意处理各种可能出现的问题,以保障分布式事务的顺利执行。
47 6
|
1月前
|
Java 数据库连接 数据库
不可不知道的Spring 框架七大模块
Spring框架是一个全面的Java企业级应用开发框架,其核心容器模块为其他模块提供基础支持,包括Beans、Core、Context和SpEL四大子模块;数据访问及集成模块支持数据库操作,涵盖JDBC、ORM、OXM、JMS和Transactions;Web模块则专注于Web应用,提供Servlet、WebSocket等功能;此外,还包括AOP、Aspects、Instrumentation、Messaging和Test等辅助模块,共同构建强大的企业级应用解决方案。
59 2