• java中使用redis2个库并支持Redis哈希表


    一个redis实例,默认包含16个库,序号从0到15。在redis命令行中,可以用select 序号来切换。我最近在做的一个项目中,需要使用redis的2个库。一个是由其他子系统写入,web后端(java)只读取;数据读出来,处理后,再写入另一个redis库,供WEB前端请求。

    同时,对Redis的操作支持哈希表。即运行过程中,可以修改哈希类型的键值。比如该值是一个Hash类型,赋值的时候,如果不存在指定元素,则添加;否则更新。这样做的好处是,该键值的元素,可由不同的步骤产生。比如写入的值,有些是同步产生的,有些是异步产生的,有先有后。

    具体如下:

    一、配置文件中设置redis信息

    redis:
        db:
            db1:
                host: 10.0.1.8
                port: 6379
                database: 5
                timeout: 6000 # 单位是毫秒
            db2:
                host: 10.0.1.8
                port: 6379
                database: 6
                timeout: 6000 # 单位是毫秒
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    二、Configuration

    1、创建一个RedisProperties类来读取配置文件信息

    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.stereotype.Component;
    
    import java.util.HashMap;
    import java.util.Map;
    
    @Component
    @ConfigurationProperties(prefix = "redis")
    public class RedisProperties {
    
        private Map<String, DatabaseProperties> db = new HashMap<>();
    
        public Map<String, DatabaseProperties> getDb() {
            return db;
        }
        public void setDb(Map<String, DatabaseProperties> db) {
            this.db = db;
        }
    
        public static class DatabaseProperties {
            private String host;
            private int port;
            private int database;
            private int timeout;
    
            public String getHost() {
                return host;
            }
    
            public void setHost(String host) {
                this.host = host;
            }
    
            public int getPort() {
                return port;
            }
    
            public void setPort(int port) {
                this.port = port;
            }
    
            public int getDatabase() {
                return database;
            }
    
            public void setDatabase(int database) {
                this.database = database;
            }
    
            public int getTimeout() {
                return timeout;
            }
    
            public void setTimeout(int timeout) {
                this.timeout = timeout;
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58

    2、Redis.config

    里面声明了2个工厂,可供产生2个redisTemplate,分别对应不同的redis数据库。

    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.boot.context.properties.EnableConfigurationProperties;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Primary;
    import org.springframework.data.redis.connection.RedisConnectionFactory;
    import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
    import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;
    import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
    import org.springframework.data.redis.serializer.StringRedisSerializer;
    
    import java.time.Duration;
    
    @Configuration
    @EnableConfigurationProperties(RedisProperties.class)
    public class RedisConfig {
    
        @Bean(name = "redisConnectionFactory1")
        @Primary
        public RedisConnectionFactory redisConnectionFactory1(RedisProperties redisProperties) {
            return createConnectionFactory(redisProperties.getDb().get("db1"));
        }
    
        @Bean(name = "redisConnectionFactory2")
        public RedisConnectionFactory redisConnectionFactory2(RedisProperties redisProperties) {
            return createConnectionFactory(redisProperties.getDb().get("db2"));
        }
    
        private RedisConnectionFactory createConnectionFactory(RedisProperties.DatabaseProperties properties) {
            RedisStandaloneConfiguration config = new RedisStandaloneConfiguration();
            config.setHostName(properties.getHost());
            config.setPort(properties.getPort());
            config.setDatabase(properties.getDatabase());
    
            LettuceClientConfiguration clientConfig = LettuceClientConfiguration.builder()
                    .commandTimeout(Duration.ofMillis(properties.getTimeout()))
                    .build();
    
            return new LettuceConnectionFactory(config, clientConfig);
        }
    
        @Bean(name = "redisTemplate1")
        @Primary
        public RedisTemplate<String, Object> redisTemplate1(
                @Qualifier("redisConnectionFactory1") RedisConnectionFactory factory) {
            return createRedisTemplate(factory);
        }
    
        @Bean(name = "redisTemplate2")
        public RedisTemplate<String, Object> redisTemplate2(
                @Qualifier("redisConnectionFactory2") RedisConnectionFactory factory) {
            return createRedisTemplate(factory);
        }
    
        private RedisTemplate<String, Object> createRedisTemplate(RedisConnectionFactory factory) {
            RedisTemplate<String, Object> template = new RedisTemplate<>();
            template.setConnectionFactory(factory);
    
            // 配置具体的序列化方式
            Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
            template.setKeySerializer(new StringRedisSerializer());
            template.setValueSerializer(jackson2JsonRedisSerializer);
            template.setHashKeySerializer(new StringRedisSerializer());
            template.setHashValueSerializer(jackson2JsonRedisSerializer);
    
            return template;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70

    三、如何使用两个 redis库?

    思路是:
    1)创建一个接口RedisService,声明各种对redis的操作
    2)针对该接口,实现redisService1和redisService2,分别使用redisTemplate1和redisTemplate2
    3)使用的时候,redisService1就是对应库1,redisService2对应库2

    具体如下:

    1、接口RedisService

    import java.util.Map;
    import java.util.Set;
    
    public interface RedisService {
        Set<String> keys(String key);
        Set<String> keysAll();
    
        String get(String key);
        String get(String key, String hashKey);
    
        void set(String key,String value);
    
        void upsertArrayElements(String hashKey, Map<String, Object> newElements);
    
        Map<Object, Object> getArrayElements(String hashKey);
    
        boolean exists(String key);
        boolean hasKey(String key, String hashKey);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    2、实现类1RedisService1Impl

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.stereotype.Service;
    
    import java.util.Map;
    import java.util.Set;
    
    @Service("redisService1")
    public class RedisService1Impl implements  RedisService{
    
        private final RedisHandler redisHandler;
    
        @Autowired
        public RedisService1Impl(@Qualifier("redisTemplate1") RedisTemplate<String, Object> redisTemplate) {
            this.redisHandler = new RedisHandler(redisTemplate);
        }
    
        @Override
        public Set<String> keys(String key){
            return redisHandler.keys(key);
        }
        @Override
        public Set<String> keysAll(){
            return redisHandler.keysAll();
        }
    
        @Override
        public String get(String key){
            return redisHandler.get(key);
        }
        @Override
        public String get(String key, String hashKey){
            return redisHandler.get(key,hashKey);
        }
    
        @Override
        public void set(String key,String value){
            redisHandler.set(key,value);
        }
    
        @Override
        public void upsertArrayElements(String hashKey, Map<String, Object> newElements) {
            // 对于每个新元素,如果它不存在于哈希表中,则添加它;如果它已经存在,则覆盖它。
            redisHandler.upsertArrayElements(hashKey,newElements);
        }
        @Override
        public Map<Object, Object> getArrayElements(String hashKey) {
            return redisHandler.getArrayElements(hashKey);
        }
    
        @Override
        public boolean exists(String key){
            return redisHandler.exists(key);
        }
        @Override
        public boolean hasKey(String key, String hashKey){
            return redisHandler.hasKey(key,hashKey);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60

    注意代码中,声明使用redisTemplate1

        @Autowired
        public RedisService1Impl(@Qualifier("redisTemplate1") RedisTemplate<String, Object> redisTemplate) {
            this.redisHandler = new RedisHandler(redisTemplate);
        }
    
    • 1
    • 2
    • 3
    • 4

    3、实现类2RedisService2Impl

    基本上与RedisService1Impl没有什么区别,只是对应的redisTemplate不一样。

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.stereotype.Service;
    
    import java.util.Map;
    import java.util.Set;
    
    @Service("redisService2")
    public class RedisService2Impl implements  RedisService{
    
        private final RedisHandler redisHandler;
    
        @Autowired
        public RedisService2Impl(@Qualifier("redisTemplate2") RedisTemplate<String, Object> redisTemplate) {
            this.redisHandler = new RedisHandler(redisTemplate);
        }
    
        @Override
        public Set<String> keys(String key){
            return redisHandler.keys(key);
        }
        @Override
        public Set<String> keysAll(){
            return redisHandler.keysAll();
        }
    
        @Override
        public String get(String key){
            return redisHandler.get(key);
        }
        @Override
        public String get(String key, String hashKey){
            return redisHandler.get(key,hashKey);
        }
    
        @Override
        public void set(String key,String value){
            redisHandler.set(key,value);
        }
    
        @Override
        public void upsertArrayElements(String hashKey, Map<String, Object> newElements) {
            // 对于每个新元素,如果它不存在于哈希表中,则添加它;如果它已经存在,则覆盖它。
            redisHandler.upsertArrayElements(hashKey,newElements);
        }
        @Override
        public Map<Object, Object> getArrayElements(String hashKey) {
            return redisHandler.getArrayElements(hashKey);
        }
    
        @Override
        public boolean exists(String key){
            return redisHandler.exists(key);
        }
        @Override
        public boolean hasKey(String key, String hashKey){
            return redisHandler.hasKey(key,hashKey);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60

    4、公共Redis操作类RedisHandler

    import com.landtool.server.modules.utils.JsonUtil;
    import org.springframework.data.redis.core.HashOperations;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.stereotype.Component;
    
    import java.util.Map;
    import java.util.Set;
    
    @Component
    public class RedisHandler {
    
        private RedisTemplate<String, Object> redisTemplate;
    
        public RedisHandler(RedisTemplate<String, Object> redisTemplate) {
            this.redisTemplate = redisTemplate;
        }
    
        /**
         * 是否存在指定key
         */
        public boolean exists(String key) {
            return redisTemplate.hasKey(key);
        }
    
        /**
         * 是否存在键
         */
        public boolean hasKey(String key, String hashKey) {
            assert key != null && hashKey != null;
            HashOperations<String, String, String> hashOperations = redisTemplate.opsForHash();
            return hashOperations.hasKey(key, hashKey);
        }
    
        /**
         * 获取所有key
         */
        public Set<String> keys(String key) {
            assert key != null;
            HashOperations<String, String, String> hashOperations = redisTemplate.opsForHash();
            return hashOperations.keys(key);
        }
    
        public Set<String> keysAll() {
            return redisTemplate.keys("*");
        }
    
        public String get(String key) {
            Object value = redisTemplate.opsForValue().get(key);
            return value != null ? value.toString() : null;
        }
        public String get(String key, String hashKey) {
            assert key != null && hashKey != null;
            HashOperations<String, String, String> hashOperations = redisTemplate.opsForHash();
            String json = null;
            try {
                json = JsonUtil.toJsonString(hashOperations.get(hashKey, key));
            } catch (Exception e) {
                e.printStackTrace();
            }
    
            return json;
        }
    
        public void set(String key, String value) {
            redisTemplate.opsForValue().set(key, value);
        }
    
        public void upsertArrayElements(String hashKey, Map<String, Object> newElements) {
            // 对于每个新元素,如果它不存在于哈希表中,则添加它;如果它已经存在,则覆盖它。
            redisTemplate.opsForHash().putAll(hashKey, newElements);
        }
    
        public Map<Object, Object> getArrayElements(String hashKey) {
            return redisTemplate.opsForHash().entries(hashKey);
        }
    
        /**
         * 删除数据
         */
        public Long delete(String key, String... hashKeys) {
            assert key != null && hashKeys != null;
            HashOperations<String, String, String> hashOperations = redisTemplate.opsForHash();
            return hashOperations.delete(key, hashKeys);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85

    四、调用RedisService

    @Autowired
    @Qualifier("redisService1")
    RedisService redisService;
    
    @Autowired
    @Qualifier("redisService2")
    RedisService redisService2;
    
    redisService.***,使用库1
    redisService2.***,使用库2
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    五、操作哈希表

    private static final String REDIS_CHECK_LINK = "check_link";
    public void freshCheckLink() {
        Map<String, Object> links = new HashMap<>();
    
        //nce
        getNce();
    
        //outer-api
        links.put("outerApi",某值);
    
        redisService2.upsertArrayElements(REDIS_CHECK_LINK,links);
    }
    private void getNce() {
        AtomicLong myCount = new AtomicLong();
        CompletableFuture.supplyAsync(() -> {
    		。。。
        }).thenAccept(count -> {
    	    Map<String, Object> links = new HashMap<>();
    	    links.put("nce",myCount.get() >= 0);
    	    redisService2.upsertArrayElements(REDIS_CHECK_LINK,links);
        });
    }
    private void setNceStatus(boolean status){
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    这样子,键名为“check_link”的结构如下:
    在这里插入图片描述

    六、小结

    Redis使用多个库有现实意义。在我这个项目中,是为了避免冲突。库1由其他子系统频繁写入,而库2则是将数据从库1读取、分析、整理后产生的结果。web前端向后端请求数据,后端直接从结果从库2读出,避免了每个请求都分析、整理。

  • 相关阅读:
    下载Python的不同版本在同一台电脑上如何共存
    进程与线程
    记一次群聊消息查询优化的实践
    【android】install android NDK
    Golang基础 函数详解 函数基础
    出海 SaaS 企业增长修炼手册2:Kyligence 落地 PLG 是如何避坑的?
    C#中错误与异常处理
    SQL: MIN Function
    Elasticsearch搜索匹配功能解析(十一)
    Hbuilderx:Vue项目打包apk打开首页空白问题
  • 原文地址:https://blog.csdn.net/leftfist/article/details/133310823