美文网首页springbootredisalready
SpringBoot集成redisson操作redis

SpringBoot集成redisson操作redis

作者: 小波同学 | 来源:发表于2022-06-23 15:58 被阅读0次

    一、配置

    1.1 引入maven

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

    1.2 配置文件

    spring.redis.database=0
    spring.redis.password=
    spring.redis.timeout=3000
    #sentinel/cluster/single
    spring.redis.mode=single
    #连接池配置
    spring.redis.pool.max-idle=16
    spring.redis.pool.min-idle=8
    spring.redis.pool.max-active=8
    spring.redis.pool.max-wait=3000
    spring.redis.pool.conn-timeout=3000
    spring.redis.pool.so-timeout=3000
    spring.redis.pool.size=10
    #单机配置
    spring.redis.single.address=192.168.60.23:6379
    #集群配置
    spring.redis.cluster.scan-interval=1000
    spring.redis.cluster.nodes=
    spring.redis.cluster.read-mode=SLAVE
    spring.redis.cluster.retry-attempts=3
    spring.redis.cluster.failed-attempts=3
    spring.redis.cluster.slave-connection-pool-size=64
    spring.redis.cluster.master-connection-pool-size=64
    spring.redis.cluster.retry-interval=1500
    #哨兵配置
    spring.redis.sentinel.master=business-master
    spring.redis.sentinel.nodes=
    spring.redis.sentinel.master-onlyWrite=true
    spring.redis.sentinel.fail-max=3
    

    1.3 配置文件读取

    /**
     * @author: huangyibo
     * @Date: 2022/6/23 10:56
     * @Description: 配置文件读取
     */
    
    @ConfigurationProperties(prefix="spring.redis", ignoreUnknownFields = false)
    @Data
    @ToString
    public class RedisProperties {
    
        private int database;
    
        /**
         * 等待节点回复命令的时间。该时间从命令发送成功时开始计时
         */
        private int timeout;
    
        private String password;
    
        private String mode;
    
    
        /**
         * 池配置
         */
        private RedisPoolProperties pool;
    
    
        /**
         * 单机信息配置
         */
        private RedisSingleProperties single;
    
    
        /**
         * 集群 信息配置
         */
        private RedisClusterProperties cluster;
    
        /**
         * 哨兵配置
         *
         */
        private RedisSentinelProperties sentinel;
    }
    
    /**
     * @author: huangyibo
     * @Date: 2022/6/23 11:00
     * @Description: redis 池配置
     */
    
    @Data
    @ToString
    public class RedisPoolProperties {
    
        private int maxIdle;
    
        private int minIdle;
    
        private int maxActive;
    
        private int maxWait;
    
        private int connTimeout;
    
        private int soTimeout;
    
        /**
         * 池大小
         */
        private int size;
    
    }
    
    /**
     * @author: huangyibo
     * @Date: 2022/6/23 11:02
     * @Description: 单节点配置
     */
    
    @Data
    @ToString
    public class RedisSingleProperties {
    
        private String address;
    }
    
    /**
     * @author: huangyibo
     * @Date: 2022/6/23 11:03
     * @Description: 集群配置
     */
    
    @Data
    @ToString
    public class RedisClusterProperties {
    
        /**
         * 集群状态扫描间隔时间,单位是毫秒
         */
        private int scanInterval;
    
        /**
         * 集群节点
         */
        private String nodes;
    
        /**
         * 默认值: SLAVE(只在从服务节点里读取)设置读取操作选择节点的模式。 可用值为: SLAVE - 只在从服务节点里读取。
         * MASTER - 只在主服务节点里读取。 MASTER_SLAVE - 在主从服务节点里都可以读取
         */
        private String readMode;
    
        /**
         * (从节点连接池大小) 默认值:64
         */
        private int slaveConnectionPoolSize;
    
        /**
         * 主节点连接池大小)默认值:64
         */
        private int masterConnectionPoolSize;
    
        /**
         * (命令失败重试次数) 默认值:3
         */
        private int retryAttempts;
    
        /**
         *命令重试发送时间间隔,单位:毫秒 默认值:1500
         */
        private int retryInterval;
    
        /**
         * 执行失败最大次数默认值:3
         */
        private int failedAttempts;
    }
    
    /**
     * @author: huangyibo
     * @Date: 2022/6/23 11:06
     * @Description: 哨兵配置
     */
    
    @Data
    @ToString
    public class RedisSentinelProperties {
    
        /**
         * 哨兵master 名称
         */
        private String master;
    
        /**
         * 哨兵节点
         */
        private String nodes;
    
        /**
         * 哨兵配置
         */
        private boolean masterOnlyWrite;
    
        /**
         *
         */
        private int failMax;
    
    }
    

    1.4 CacheConfiguration

    import org.redisson.Redisson;
    import org.redisson.api.RedissonClient;
    import org.redisson.config.*;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
    import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
    import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
    import org.springframework.boot.context.properties.EnableConfigurationProperties;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.util.StringUtils;
    
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.List;
    
    /**
     * @author: huangyibo
     * @Date: 2022/6/23 11:08
     * @Description:
     */
    
    @Configuration
    @EnableConfigurationProperties(RedisProperties.class)
    public class CacheConfiguration {
    
        @Autowired
        private RedisProperties redisProperties;
    
        @Configuration
        @ConditionalOnClass({Redisson.class})
        @ConditionalOnExpression("'${spring.redis.mode}'=='single' or '${spring.redis.mode}'=='cluster' or '${spring.redis.mode}'=='sentinel'")
        protected class RedissonSingleClientConfiguration {
    
            /**
             * 单机模式 redisson 客户端
             */
    
            @Bean
            @ConditionalOnProperty(name="spring.redis.mode", havingValue="single")
            public RedissonClient redissonSingle() {
                Config config = new Config();
                String node = redisProperties.getSingle().getAddress();
                node = node.startsWith("redis://") ? node : "redis://" + node;
                SingleServerConfig serverConfig = config.useSingleServer()
                        .setAddress(node)
                        .setTimeout(redisProperties.getPool().getConnTimeout())
                        .setConnectionPoolSize(redisProperties.getPool().getSize())
                        .setConnectionMinimumIdleSize(redisProperties.getPool().getMinIdle());
                if(!StringUtils.isEmpty(redisProperties.getPassword())) {
                    serverConfig.setPassword(redisProperties.getPassword());
                }
                return Redisson.create(config);
            }
    
            /**
             * 集群模式的 redisson 客户端
             *
             * @return
             */
            @Bean
            @ConditionalOnProperty(name = "spring.redis.mode", havingValue = "cluster")
            public RedissonClient redissonCluster() {
                System.out.println("cluster redisProperties:" + redisProperties.getCluster());
    
                Config config = new Config();
                String[] nodes = redisProperties.getCluster().getNodes().split(",");
                List<String> newNodes = new ArrayList<>(nodes.length);
                Arrays.stream(nodes).forEach((index) -> newNodes.add(
                    index.startsWith("redis://") ? index : "redis://" + index)
                );
    
                ClusterServersConfig serverConfig = config.useClusterServers()
                        .addNodeAddress(newNodes.toArray(new String[0])
                        ).setScanInterval(
                            redisProperties.getCluster().getScanInterval()
                        ).setIdleConnectionTimeout(
                            redisProperties.getPool().getSoTimeout()
                        ).setConnectTimeout(
                            redisProperties.getPool().getConnTimeout()
                        ).setRetryAttempts(
                            redisProperties.getCluster().getRetryAttempts()
                        ).setRetryInterval(
                            redisProperties.getCluster().getRetryInterval()
                        ).setMasterConnectionPoolSize(
                                redisProperties.getCluster().getMasterConnectionPoolSize()
                        ).setSlaveConnectionPoolSize(
                                redisProperties.getCluster().getSlaveConnectionPoolSize()
                        ).setTimeout(
                                redisProperties.getTimeout()
                        );
    
                if (!StringUtils.isEmpty(redisProperties.getPassword())) {
                    serverConfig.setPassword(redisProperties.getPassword());
                }
                return Redisson.create(config);
            }
    
    
            /**  
             * 哨兵模式 redisson 客户端
             * @return
             */
            @Bean
            @ConditionalOnProperty(name = "spring.redis.mode", havingValue = "sentinel")
            public RedissonClient redissonSentinel() {
                System.out.println("sentinel redisProperties:" + redisProperties.getSentinel());
                Config config = new Config();
                String[] nodes = redisProperties.getSentinel().getNodes().split(",");
                List<String> newNodes = new ArrayList<>(nodes.length);
                Arrays.stream(nodes).forEach((index) -> newNodes.add(
                    index.startsWith("redis://") ? index : "redis://" + index)
                );
    
                SentinelServersConfig serverConfig = config.useSentinelServers()
                        .addSentinelAddress(newNodes.toArray(new String[0]))
                        .setMasterName(redisProperties.getSentinel().getMaster())
                        .setReadMode(ReadMode.SLAVE)
                        .setTimeout(redisProperties.getTimeout())
                        .setMasterConnectionPoolSize(redisProperties.getPool().getSize())
                        .setSlaveConnectionPoolSize(redisProperties.getPool().getSize());
    
                if (!StringUtils.isEmpty(redisProperties.getPassword())) {
                    serverConfig.setPassword(redisProperties.getPassword());
                }
                return Redisson.create(config);
            }
        }
    }
    

    二、Redisson工具类

    import org.redisson.api.*;
    import org.redisson.client.codec.StringCodec;
    import org.springframework.stereotype.Component;
    
    import javax.annotation.Resource;
    import java.util.concurrent.TimeUnit;
    
    /**
     * @author: huangyibo
     * @Date: 2022/6/23 15:01
     * @Description:
     */
    
    @Component
    public class RedisUtils {
    
        /**
         * 默认缓存时间
         */
        private static final Long DEFAULT_EXPIRED = 32000L;
    
        
        /**
         * 自动装配redisson client对象
         */
        @Resource
        private RedissonClient redissonClient;
    
        
        /**
         * 用于操作key
         * @return RKeys 对象
         */
        public RKeys getKeys() {
            return redissonClient.getKeys();
        }
        
        
        /**
         * 移除缓存
         *
         * @param key
         */
        public void delete(String key) {
            redissonClient.getBucket(key).delete();
        }
    
        
        /**
         * 获取getBuckets 对象
         *
         * @return RBuckets 对象
         */
        public RBuckets getBuckets() {
            return redissonClient.getBuckets();
        }
    
        
        /**
         * 读取缓存中的字符串,永久有效
         *
         * @param key 缓存key
         * @return 字符串
         */
        public String getStr(String key) {
            RBucket<String> bucket = redissonClient.getBucket(key);
            return bucket.get();
        }
    
        
        /**
         * 缓存字符串
         *
         * @param key
         * @param value
         */
        public void setStr(String key, String value) {
            RBucket<String> bucket = redissonClient.getBucket(key);
            bucket.set(value);
        }
    
        
        /**
         * 缓存带过期时间的字符串
         *
         * @param key     缓存key
         * @param value   缓存值
         * @param expired 缓存过期时间,long类型,必须传值
         */
        public void setStr(String key, String value, long expired) {
            RBucket<String> bucket = redissonClient.getBucket(key, StringCodec.INSTANCE);
            bucket.set(value, expired <= 0L ? DEFAULT_EXPIRED : expired, TimeUnit.SECONDS);
        }
    
        
        /**
         * string 操作,如果不存在则写入缓存(string方式,不带有redisson的格式信息)
         *
         * @param key     缓存key
         * @param value   缓存值
         * @param expired 缓存过期时间
         */
        public Boolean setIfAbsent(String key, String value, long expired) {
            RBucket<String> bucket = redissonClient.getBucket(key, StringCodec.INSTANCE);
            return bucket.trySet(value, expired <= 0L ? DEFAULT_EXPIRED : expired, TimeUnit.SECONDS);
        }
    
        
        /**
         * 如果不存在则写入缓存(string方式,不带有redisson的格式信息),永久保存
         *
         * @param key   缓存key
         * @param value 缓存值
         */
        public Boolean setIfAbsent(String key, String value) {
            RBucket<String> bucket = redissonClient.getBucket(key, StringCodec.INSTANCE);
            return bucket.trySet(value);
        }
    
        
        /**
         * 判断缓存是否存在
         *
         * @param key
         * @return true 存在
         */
        public Boolean isExists(String key) {
            return redissonClient.getBucket(key).isExists();
        }
    
        
        /**
         * 获取RList对象
         *
         * @param key RList的key
         * @return RList对象
         */
        public <T> RList<T> getList(String key) {
            return redissonClient.getList(key);
        }
    
        
        /**
         * 获取RMapCache对象
         *
         * @param key
         * @return RMapCache对象
         */
        public <K, V> RMapCache<K, V> getMap(String key) {
            return redissonClient.getMapCache(key);
        }
    
        
        /**
         * 获取RSET对象
         *
         * @param key
         * @return RSET对象
         */
        public <T> RSet<T> getSet(String key) {
            return redissonClient.getSet(key);
        }
    
        
        /**
         * 获取RScoredSortedSet对象
         *
         * @param key
         * @param <T>
         * @return RScoredSortedSet对象
         */
        public <T> RScoredSortedSet<T> getScoredSortedSet(String key) {
            return redissonClient.getScoredSortedSet(key);
        }
    }
    

    三、常用RKeys的API操作

    每个Redisson对象实例都会有一个与之对应的Redis数据实例,可以通过调用getName方法来取得redis数据实例的名称(key),所有于Redis key相关的操作都归纳在RKeys这个接口里。

    RKeys keys = client.getKeys();
    //获取所有key值
    Iterable<String> allKeys = keys.getKeys();
    //模糊查询所有包含关键字key的值
    Iterable<String> foundedKeys = keys.getKeysByPattern("key");
    //删除多个key值
    long numOfDeletedKeys = keys.delete("obj1", "obj2", "obj3");
    //模糊删除key值
    long deletedKeysAmount = keys.deleteByPattern("test?");
    //随机获取key
    String randomKey = keys.randomKey();
    //查询当前有多少个key
    long keysAmount = keys.count();
    

    具体demo

    private void getKeys() {
        RKeys keys = redisUtils.getRedisKeys();
        Iterable<String> allKeys = keys.getKeys();
        StringBuilder sb = new StringBuilder();
        for (String key : allKeys) {
            sb = sb.append(key).append(",");
        }
        log.info("所有的key:{}", sb.substring(0, sb.length() - 1));
        // 模糊查询以 map 打头的所有 key
        allKeys = keys.getKeysByPattern("map*");
        sb = new StringBuilder();
        for (String key : allKeys) {
            sb = sb.append(key).append(",");
        }
        log.info("模糊匹配到的key:{}", sb.substring(0, sb.length() - 1));
    }
    

    其中,getKeysByPattern是基于redis的scan命令实现。

    四、通用对象桶Object Bucket

    Redisson的分布式RBucket Java对象是一种通用对象桶,可以用来存放任意类型的对象。除了同步接口外,还提供异步(Async)、反射式(Reactive)和RxJava2标准的接口。还可以通过RBuckets接口实现批量操作多个RBucket对象。

    /**
     * String 数据类型
     */
    private void strDemo() {
        redisUtils.setStr(DEMO_STR, "Hello, String.");
        log.info("String 测试数据:{}", redisUtils.getStr(DEMO_STR));
        redisUtils.setStr("myBucket", "myBucketIsXxx");
        RBuckets buckets = redisUtils.getBuckets();
        Map<String, String> foundBuckets = buckets.get("myBucket*");
        Map<String, Object> map = new HashMap<>();
        map.put("myBucket1", "value1");
        map.put("myBucket2", 30L);
    
        // 同时保存全部通用对象桶。
        buckets.set(map);
        Map<String, String> loadedBuckets = buckets.get("myBucket1", "myBucket2", "myBucket3");
        log.info("跨桶String 测试数据:{}", loadedBuckets);
        map.put("myBucket3", 320L);
    }
    

    五、散列 Hash

    基于Redisson的分布式映射结构的RMap Java对象实现了java.util.concurrent.ConcurrentMap和java.util.Map接口,与HashMap不同的是,RMap 保持了元素的插入顺序。该对象的最大容量受Redis限制,最大元素数量是4294967295个。

    /**
     * Hash类型
     */
    private void hashDemo() {
        RMap<Object, Object> map = redisUtils.getMap("mapDemo");
        map.put("demoId1", "123");
        map.put("demoId100", "13000");
        Object demoId1Obj = map.get("demoId1");
        log.info("Hash 测试数据:{}", demoId1Obj);
    }
    

    六、集合 Set

    基于Redisson的分布式Set结构的RSet Java对象实现了java.util.Set接口,通过元素的互相状态比较保证了每个元素的唯一性,该对象的最大容量受Redis限制,最大元素数量是4294967295个。

    /**
     * Set 测试
     */
    private void setDemo() {
        RSet<String> set = redisUtils.getSet("setKey");
        set.add("value777");
        log.info("Set 测试数据");
        Iterator<String> iterator = set.iterator();
        while (iterator.hasNext()) {
            String next = iterator.next();
            log.info(next);
        }
    }
    

    七、列表 List

    基于Redisson的分布式列表 List 结构的RList Java对象在实现了java.util.List接口的同时,确保了元素插入时的顺序,该对象的最大容量受Redis限制,最大元素数量是4294967295个。

    /**
     * List数据类型
     */
    private void listDemo() {
        RList<String> list = redisUtils.getList("listDemo");
        list.add("listValue1");
        list.add("listValue2");
    
        log.info("List 测试数据:{}", list.get(1));
    }
    

    综合示例

    将上述demo放入一个API中,快速测试:

    import lombok.extern.slf4j.Slf4j;
    import org.redisson.api.*;
    import org.springframework.web.bind.annotation.ModelAttribute;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.RestController;
    
    import javax.annotation.Resource;
    import java.util.HashMap;
    import java.util.Iterator;
    import java.util.Map;
    
    @Slf4j
    @RestController
    @RequestMapping(value = "/redisson", method = RequestMethod.POST)
    public class StudyRedissonController {
    
        @Resource
        private RedisUtils redisUtils;
    
        private static String DEMO_STR = "demoStr";
    
        @PostMapping("/learnRedisson")
        public void learnRedisson() {
            //三种数据结构使用示例
            strDemo();
            hashDemo();
            listDemo();
            setDemo();
            getKeys();
        }
    
        private void getKeys() {
            RKeys keys = redisUtils.getKeys();
            Iterable<String> allKeys = keys.getKeys();
            StringBuilder sb = new StringBuilder();
            for (String key : allKeys) {
                sb = sb.append(key).append(",");
            }
            log.info("所有的key:{}", sb.substring(0, sb.length() - 1));
            // 模糊查询以 map 打头的所有 key
            allKeys = keys.getKeysByPattern("map*");
            sb = new StringBuilder();
            for (String key : allKeys) {
                sb = sb.append(key).append(",");
            }
            log.info("模糊匹配到的key:{}", sb.substring(0, sb.length() - 1));
        }
        /**
         * Hash类型
         */
        private void hashDemo() {
            RMap<Object, Object> map = redisUtils.getMap("mapDemo");
            map.put("demoId1", "123");
            map.put("demoId100", "13000");
            Object demoId1Obj = map.get("demoId1");
            log.info("Hash 测试数据:{}", demoId1Obj);
        }
    
        /**
         * String 数据类型
         */
        private void strDemo() {
            redisUtils.setStr(DEMO_STR, "Hello, String.");
            log.info("String 测试数据:{}", redisUtils.getStr(DEMO_STR));
            redisUtils.setStr("myBucket", "myBucketIsXxx");
            RBuckets buckets = redisUtils.getBuckets();
            Map<String, String> foundBuckets = buckets.get("myBucket*");
            Map<String, Object> map = new HashMap<>();
            map.put("myBucket1", "value1");
            map.put("myBucket2", 30L);
    
            // 同时保存全部通用对象桶。
            buckets.set(map);
            Map<String, String> loadedBuckets = buckets.get("myBucket1", "myBucket2", "myBucket3");
            log.info("跨桶String 测试数据:{}", loadedBuckets);
            map.put("myBucket3", 320L);
        }
    
        /**
         * List数据类型
         */
        private void listDemo() {
            RList<String> list = redisUtils.getList("listDemo");
            list.add("listValue1");
            list.add("listValue2");
    
            log.info("List 测试数据:{}", list.get(1));
        }
        /**
         * Set 测试
         */
        private void setDemo() {
            RSet<String> set = redisUtils.getSet("setKey");
            set.add("value777");
            log.info("Set 测试数据");
            Iterator<String> iterator = set.iterator();
            while (iterator.hasNext()) {
                String next = iterator.next();
                log.info(next);
            }
        }
    
    }
    

    参考:
    https://blog.51cto.com/u_14028890/2308518

    https://www.cnblogs.com/east7/p/16255253.html

    https://www.cnblogs.com/east7/p/16255305.html

    相关文章

      网友评论

        本文标题:SpringBoot集成redisson操作redis

        本文链接:https://www.haomeiwen.com/subject/bqfmvrtx.html