Redis - 在项目中使用Redis

1. 非Spring框架中使用

  1. 依赖
    最常用的Redis在Java上的开发包就是jedis.jar,同时也需要导入commons-pool2.jar用作连接池的组件依赖包。注意commons-pool2的版本最好保持最新,过低版本可能导致无法使用。这里做示例的版本是:jedis-2.9.3.jar和commons-pool2-2.8.0.jar。
  2. 工具类
    import redis.clients.jedis.Jedis;
    import redis.clients.jedis.JedisPool;
    import redis.clients.jedis.JedisPoolConfig;
    
    public class RedisUtil {
        // Redis所在主机的IP地址
        private static String URL = "127.0.0.1";
        // Redis所在主机的端口
        private static int PORT = 6379;
        // Redis最大实例数,也就是连接池最大同时活跃的连接数量,默认8
        private static int MAX_TOTAL = 64;
        // Redis连接池控制的空闲连接数量,默认8
        private static int MAX_IDLE = 16;
        // 向连接池获取连接超时报错时长(毫秒)
        private static int MAX_WAIT = 20000;
        // 连接Redis服务端超时时长(毫秒)
        private static int TIMEOUT = 10000;
        // 获取jedis实例以前进行验证实例有效性
        private static boolean TEST_ON_BORROW = true;
        // jedis连接池
        private static JedisPool jedisPool = null;
    
        static {
            try {
                JedisPoolConfig config = new JedisPoolConfig();
                // 老版本中叫MaxActive()
                config.setMaxTotal(MAX_TOTAL);
                config.setMaxIdle(MAX_IDLE);
                // 老版本中叫MaxWait
                config.setMaxWaitMillis(MAX_WAIT);
                config.setTestOnBorrow(TEST_ON_BORROW);
                jedisPool = new Jedis(config, URL, PORT, TIMEOUT);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        // 获取连接
        public synchronized static Jedis getJedis() {
            Jedis redis;
            try {
                if (jedisPool != null) {
                    redis = jedisPool.getResource();
                    return redis;
                } else {
                    return null;
                }
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }
    
        // 释放链接
        public static void returnResource(final Jedis jedis) {
            if (jedis != null) {
                // 新版本中returnResource()方法已经弃用,官方推荐使用Pool类的close()方法释放连接
                jedisPool.close();
            }
        }
    }
    
  3. 使用
    // 要连接的Redis库
    private static final int redisDB = 0;
    // 连接对象
    private static Jedis redis = null;
    
    // 连接
    private static boolean connectionRedis() {
        redis = RedisUtil.getJedis();
        if (redis == null || !"PONE".equals(redis.ping())) {
            return false;
        }
        redis.select(redisDB);
        return true;
    }
    
    // 使用
    private static void useRedis() {
        if (this.connectionRedis()) {
            redis.set("key", "value");
            // 切记释放连接
            RedisUtil.returnResource(redis);
        }
    }
    

2. 在SpringBoot中的使用

  1. Maven依赖配置
    <!-- springboot 1.5.x 是Jdeis实现,2.x版本以后使用更安全高效的Lettuce实现 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
    <!-- Lettuce实现方式需要引入pool2类库 -->
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-pool2</artifactId>
    </dependency>
    <!-- jackson依赖用来修改序列化方式 -->
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.12.0</version>
    </dependency>
    
  2. application.yml参数配置
    spring:
      redis:
        database: 0
        host: 127.0.0.1
        port: 6379
        timeout: 5000
        lettuce:
          pool:
            max-active: 8
            max-wait: -1
            max-idle: 8
            min-idle: 0
    
  3. 修改默认序列化方式
    import com.fasterxml.jackson.databind.ObjectMapper;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.data.redis.connection.RedisConnectionFactory
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
    import org.springframework.data.redis.serializer.StringRedisSerializer;
    
    @Configuration
    public class RedisConfig {
        @Bean
        RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) {
            RedisTemplate redisTemplate = new RedisTemplate();
            redisTemplate.setConnectionFactory(redisConnectionFactory);
    
            Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
            jackson2JsonRedisSerializer.setObjectMapper(new ObjectMapper());
    
            redisTemplate.setKeySerializer(new StringRedisSerializer());
            // 这里的处理会对保存在Redis中字符串类型的value值最外层添加英文双引号,但取出时会自动去掉
            // 应该是为了避免读写JSON类型字符串出现问题的解决办法
            redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
    
            redisTemplate.setHashKeySerializer(new StringRedisSerializer());
            redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
    
            return redisTemplate
        }
    }
    
  4. 工具类
    @Component
    public class RedisUtil {
        private static final Logger LOGGER = LoggerFactory.getLogger(RedisUtil.class);
    
        @Resource
        private RedisTemplate redisTemplate;
    
        // ==================== Public ====================
        /**
         * redis是否可用
         *
         * @return boolean 是否可用
         */
        public boolean hasLive() {
            return "PONG".equals(redisTemplate.execute((RedisCallback<String>) RedisConnectionCommands::ping));
        }
    
        // ==================== Key ====================
        /**
         * 给key设置缓存时间
         *
         * @param key 键
         * @param time 时间(秒)
         * @return boolean 是否设置成功
         */
        public boolean expire(String key, long time) {
            try {
                redisTemplate.expire(key, time, TimeUnit.SECONDS);
                return true;
            } catch (RuntimeException e) {
                LOGGER.error("Set key  expire is failed. ", e);
                return false;
            }
        }
    
        /**
         * 根据key获取缓存时间
         *
         * @param key 键
         * @return long 时间(秒) 0代表永久有效
         */
        public long getExpire(String key) {
            return redisTemplate.getExpire(key, TimeUnit.SECONDS);
        }
    
        /**
         * 判断key是否存在
         *
         * @param key 键
         * @return boolean 是否存在
         */
        public boolean hasKey(String key) {
            try {
                return redisTemplate.hasKey(key);
            } catch (RuntimeException e) {
                LOGGER.error("hasKey is failed. ", e);
                return false;
            }
        }
    
        /**
         * 删除key-value
         *
         * @param key 一个或多个键
         */
        public void del(String... key) {
            if (key != null && key.length > 0) {
                if (key.length == 1) {
                    redisTemplate.delete(key[0]);
                } else {
                    redisTemplate.delete(CollectionUtils.arrayToList(key));
                }
            }
        }
    
        // ==================== String ====================
        /**
         * 根据key获取字符串类型的value
         *
         * @param key 键
         * @return Object 值
         */
        public Object get(String key) {
            return key == null ? null : redisTemplate.opsForValue().get(key);
        }
    
        /**
         * 设置字符串值
         *
         * @param key 键
         * @param value 值
         * @return boolean 是否设置成功
         */
        public boolean set(String key, Object value) {
            try {
                redisTemplate.opsForValue(key, value);
                return true;
            } catch (RuntimeException e) {
                LOGGER.error("Set key is failed. ", e);
                return false;
            }
        }
    
        /**
         * 设置字符串值并设置存活时长(秒)
         *
         * @param key 键
         * @param value 值
         * @param time 时间(秒),如果设置≤0则为无限期
         * @return boolean 是否设置成功
         */
        public boolean set(String key, Object value, long time) {
            try {
                if (time > 0) {
                    redisTemplate.opsForValue(key, value, time, TimeUnit.SECONDS);
                } else {
                    set(key, value);
                }
                return true;
            } catch (RuntimeException e) {
                LOGGER.error("Set key&Time is failed. ", e);
                return false;
            }
        }
    
        /**
         * 递增
         *
         * @param key 键
         * @param value 增加多少(>0)
         * @return long 递增后的值
         */
        public lang incr(String key, long value) {
            if (value <= 0) {
                LOGGER.error("incr value must greater than 0");
            }
            return redisTemplate.opsForValue().increment(key, value);
        }
    
        /**
         * 递减
         *
         * @param key 键
         * @param value 减少多少(>0)
         * @return long 递减后的值
         */
        public lang decr(String key, long value) {
            if (value <= 0) {
                LOGGER.error("decr value must greater than 0");
            }
            return redisTemplate.opsForValue().increment(key, -value);
        }
    
        // ==================== Hash ====================
        /**
         * 根据key获取Hash某项的值
         *
         * @param key 键
         * @param item 项
         * @return Object 值
         */
        public Object hGet(String key, String item) {
            return redisTemplate.opsForHash().get(key, item);
        }
    
        /**
         * 根据key获取Hash所有项的值
         *
         * @param key 键
         * @return Map<Object, Object> 多个键值
         */
        public Object hmGet(String key, String item) {
            return redisTemplate.opsForHash().entries(key, item);
        }
    
        /**
         * 设置Hash值多个键值
         *
         * @param key 键
         * @param map 多个键值
         * @return boolean 是否设置成功
         */
        public boolean hmSet(String key, Map<String, Object> map) {
            try {
                redisTemplate.opsForHash.putAll(key, map);
                return true;
            } catch (RuntimeException e) {
                LOGGER.error("Set HashMap is failed. ", e);
                return false;
            }
        }
    
        /**
         * 设置Hash值多个键值并设置存活时长(秒)
         *
         * @param key 键
         * @param map 多个键值
         * @param time 时间(秒),如果设置≤0则为无限期
         * @return boolean 是否设置成功
         */
        public boolean hmSet(String key, Map<String, Object> map, long time) {
            try {
                redisTemplate.opsForHash.putAll(key, map);
                if (time > 0) {
                    expire(key, time);
                }
                return true;
            } catch (RuntimeException e) {
                LOGGER.error("Set HashMap&Time is failed. ", e);
                return false;
            }
        }
    
        /**
         * 向Hash中存放数据,如果Hash不存在则创建
         *
         * @param key 键
         * @param item 项
         * @param value 值
         * @return boolean 是否设置成功
         */
        public boolean hSet(String key, String item, Object value) {
            try {
                redisTemplate.opsForHash.put(key, item, value);
                return true;
            } catch (RuntimeException e) {
                LOGGER.error("Set hset is failed. ", e);
                return false;
            }
        }
    
        /**
         * 向Hash中存放数据并设置存活时长(秒),如果Hash不存在则创建
         *
         * @param key 键
         * @param item 项
         * @param value 值
         * @param time 时间(秒),如果Hash已存在则会覆盖已有时间
         * @return boolean 是否设置成功
         */
        public boolean hSet(String key, String item, Object value) {
            try {
                redisTemplate.opsForHash.put(key, item, value);
                if (time > 0) {
                    expire(key, time);
                }
                return true;
            } catch (RuntimeException e) {
                LOGGER.error("Set hset&Time is failed. ", e);
                return false;
            }
        }
    
        /**
         * 删除Hash中的值
         *
         * @param key 键
         * @param item 一个或多个项
         */
        public void hDel(String key, Object... item) {
            redisTemplate.opsForHash().delete(key, item);
        }
    
        /**
         * 判断Hash中是否有指定项的值
         *
         * @param key 键
         * @param item 项
         * @return boolean 是否存在
         */
        public boolean hHasKey(String key, String item) {
            return redisTemplate.opsForHash().hasKey(key, item);
        }
    
        /**
         * 递增
         *
         * @param key 键
         * @param item 项
         * @param value 增加多少(>0)
         * @return long 递增后的值
         */
        public lang hIncr(String key, String item, double value) {
            return redisTemplate.opsForHash().increment(key, item, value);
        }
    
        /**
         * 递减
         *
         * @param key 键
         * @param item 项
         * @param value 减少多少(>0)
         * @return long 递减后的值
         */
        public lang hDecr(String key, String item, double value) {
            return redisTemplate.opsForHash().increment(key, item, -value);
        }
    
        // ==================== Set ====================
        /**
         * 根据key获取Set的所有值
         *
         * @param key 键
         * @return Set<Object> 值
         */
        public Set<Object> sGet(String key) {
            try {
                return redisTemplate.opsForSet().members(key);
            } catch (RuntimeException e) {
                LOGGER.error("Get Set is failed. ", e);
                return null;
            }
        }
    
        /**
         * 根据值判断在Set中是否存在
         *
         * @param key 键
         * @param value 值
         * @return boolean 是否存在
         */
        public Set<Object> sHasKey(String key, Object value) {
            try {
                return redisTemplate.opsForSet().isMember(key, item);
            } catch (RuntimeException e) {
                LOGGER.error("Get sHasKey is failed. ", e);
                return false;
            }
        }
    
        /**
         * 将一个或多个数据放入Set,如果Set不存在则创建
         *
         * @param key 键
         * @param value 一个或多个值
         * @return long 成功个数
         */
        public long sSet(String key, Object... value) {
            try {
                return redisTemplate.opsForSet().add(key, item);
            } catch (RuntimeException e) {
                LOGGER.error("Set sSet is failed. ", e);
                return 0;
            }
        }
    
        /**
         * 将一个或多个数据放入Set并设置存活时长(秒),如果Set不存在则创建
         *
         * @param key 键
         * @param value 一个或多个值
         * @param time 时间(秒),如果Set已存在则会覆盖已有时间
         * @return long 成功个数
         */
        public long sSetAndTime(String key, Object... value, long time) {
            try {
                Long count = redisTemplate.opsForSet().add(key, item);
                if (time > 0) {
                    expire(key, time);
                }
                return count != null ? count : 0;
            } catch (RuntimeException e) {
                LOGGER.error("Set sSet is failed. ", e);
                return 0;
            }
        }
    
        /**
         * 获得Set中值的个数
         *
         * @param key 键
         * @return long 值数量
         */
        public long sGetSetSize(String key) {
            try {
                return redisTemplate.opsForSet().size(key);
            } catch (RuntimeException e) {
                LOGGER.error("Get Set size is failed. ", e);
                return 0;
            }
        }
    
        /**
         * 删除Set中的值
         *
         * @param key 键
         * @param values 一个或多个值
         * @return long 删除值数量
         */
        public long setRemove(String key, Object... values) {
            try {
                return redisTemplate.opsForSet().remove(key, values);
            } catch (RuntimeException e) {
                LOGGER.error("Remove Set values is failed. ", e);
                return 0;
            }
        }
    
        // ==================== List ====================
        /**
         * 获取List指定区间的值
         *
         * @param key 键
         * @param start 开始下标
         * @param end 结束下标
         * @return List<Object> 值
         */
        public Set<Object> lGet(String key, long start, long end) {
            try {
                return redisTemplate.opsForList().range(key, start, end);
            } catch (RuntimeException e) {
                LOGGER.error("Get List is failed. ", e);
                return null;
            }
        }
    
        /**
         * 获得List的列表长度
         *
         * @param key 键
         * @return long 列表长度
         */
        public long lGetListSize(String key) {
            try {
                return redisTemplate.opsForList().size(key);
            } catch (RuntimeException e) {
                LOGGER.error("Get List size is failed. ", e);
                return 0;
            }
        }
    
        /**
         * 通过索引,获取List中的一个值
         *
         * @param key 键
         * @param index 索引,0为第一个值,1为第二个值,-1为倒数第一个值,以此类推
         * @return Object 值
         */
        public Object lGetIndex(String key, long index) {
            try {
                return redisTemplate.opsForList().index(key, index);
            } catch (RuntimeException e) {
                LOGGER.error("Get List by index is failed. ", e);
                return null;
            }
        }
    
        /**
         * 添加List的一个值,如果List不存在则创建
         *
         * @param key 键
         * @param value 值
         * @return boolean 是否成功
         */
        public boolean lSet(String key, Object value) {
            try {
                redisTemplate.opsForList().rightPush(key, value);
                return true;
            } catch (RuntimeException e) {
                LOGGER.error("Set List is failed. ", e);
                return false;
            }
        }
    
        /**
         * 添加List的一个值并设置存活时长(秒),如果List不存在则创建
         *
         * @param key 键
         * @param value 值
         * @param time 时间(秒),如果Set已存在则会覆盖已有时间
         * @return boolean 是否成功
         */
        public boolean lSet(String key, Object value, long time) {
            try {
                redisTemplate.opsForList().rightPush(key, value);
                if (time > 0) {
                    expire(key, time);
                }
                return true;
            } catch (RuntimeException e) {
                LOGGER.error("Set List&Time is failed. ", e);
                return false;
            }
        }
    
        /**
         * 添加List的多个值,如果List不存在则创建
         *
         * @param key 键
         * @param value 值
         * @return boolean 是否成功
         */
        public boolean lSet(String key, List<Object> value) {
            try {
                redisTemplate.opsForList().rightPushAll(key, value);
                return true;
            } catch (RuntimeException e) {
                LOGGER.error("Set List is failed. ", e);
                return false;
            }
        }
    
        /**
         * 添加List的多个值并设置存活时长(秒),如果List不存在则创建
         *
         * @param key 键
         * @param value 值
         * @param time 时间(秒),如果Set已存在则会覆盖已有时间
         * @return boolean 是否成功
         */
        public boolean lSet(String key, List<Object> value, long time) {
            try {
                redisTemplate.opsForList().rightPushAll(key, value);
                if (time > 0) {
                    expire(key, time);
                }
                return true;
            } catch (RuntimeException e) {
                LOGGER.error("Set List&Time is failed. ", e);
                return false;
            }
        }
    
        /**
         * 根据索引修改List的某项的值
         *
         * @param key 键
         * @param index 索引,0为第一个值,1为第二个值,-1为倒数第一个值,以此类推
         * @return boolean 是否成功
         */
        public boolean lUpdateIndex(String key, long index, Object value) {
            try {
                redisTemplate.opsForList().set(key, index, value);
                return true;
            } catch (RuntimeException e) {
                LOGGER.error("Set List by index is failed. ", e);
                return false;
            }
        }
    
        /**
         * 删除List多个值为value的项目
         *
         * @param key 键
         * @param count 要删除数量
         * @param value 值
         * @return long 已删除数量
         */
        public long lSet(String key, long count, Object value) {
            try {
                Long remove = redisTemplate.opsForList().remove(key, count, value);
                return remove != null ? remove : 0;
            } catch (RuntimeException e) {
                LOGGER.error("Remove List is failed. ", e);
                return 0;
            }
        }
    
        // ==================== Sort Set ====================
        /**
         * Sort Set添加元素
         *
         * @param key 键
         * @param value 值
         * @param score 分数
         * @return boolean 是否添加成功
         */
        public boolean zSet(String key, Object value, double score) {
            return redisTemplate.opsForZSet().add(key, value, score);
        }
    
        /**
         * 获取Sort Set指定成员的分数
         *
         * @param key 键
         * @param value 值
         * @return long 成员的分数
         */
        public boolean getZSetScore(String key, Object value) {
            Double score = redisTemplate.opsForZSet().score(key, value);
            return score == null ? 0 : score.longValue();
        }
    
        /**
         * 获取Sort Set中指定区间成员的排名,并按照score值从大到小排序
         *
         * @param key 键
         * @param start 开始
         * @param end 结束
         * @return Set<ZSetOperations.TypendTuple> 成员集合
         */
        public boolean getZSetRank(String key, long start, long end) {
            return redisTemplate.opsForZSet().reverseRangeWithScores(key, start, end);
        }
    }
    
  5. 使用
    @Service
    public class TestUseRedis {
        @Resource
        private RedisUtil redisUtil;
    
        private void testUse() {
            if (!redisUtil.hasLive()) {
                return;
            }
            redisUtil.set("test", "测试");
            Object result = redisUtil.get("test");
            if (result instanceof String) {
                System.out.println((String) result);
            }
        }
    }
    

3. 场景:在Redis中保存和读取对象

  1. 说明
    要将JavaBean对象保存到Redis中,使用Hash数据格式保存和读取都过于繁琐,这里就使用到了JavaBean的序列化和反序列化后将数据以String数据类型保存来实现。
  2. 序列化和反序列化工具类
    import java.io.ByteArrayInputStream;
    import java.io.ByteArrayOutputStream;
    import java.io.IOException;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    
    public class BeanUtil {
        // 序列化
        public static byte[] serialize(Object object) {
            ObjectOutputStream oos;
            ByteArrayOutputStream baos;
            try {
                baos = new ByteArrayOutputStream();
                oos = new ObjectOutputStream(baos);
                oos.writeObject(object);
                return baos.toByteArray();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return null;
        }
    
        // 反序列化
        public static Object unserizlize(byte[] binaryByte) {
            ObjectInputStream ois;
            ByteArrayInputStream bais = new ByteArrayInputStream(binaryByte);
            try {
                ois = new ObjectInputStream(bais);
                return ois.readObject();
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
    }
    
  3. 使用
    // 存
    redis.set("key".getByte(StandardCharsets.UTF_8), BeanUtil.serialize(entity));
    // 取
    Entity pe = (Entity) BeanUtil.unserizlize(redis.get("key".getByte(StandardCharsets.UTF_8)));
    
posted @ 2022-07-02 15:30  苍凉温暖  阅读(231)  评论(0编辑  收藏  举报