vlambda博客
学习文章列表

微服务框架【第8期】--SpringBoot整合SpringDataRedis

微服务框架【第8期】--SpringBoot整合SpringDataRedis

导读:

    大家好,我是老田。今天我们继续梳理SpringBoot整合SpringDataRedis。重点是SpringDataJpa提供的API。

1.SpringDataRedis简介

SpringDataRedis是spring大家族中的一部分,提供了 RedisTemplate 可以在 Spring 应用中更简便的访问 Redis 以及异常处理及序列化,支持发布订阅等操作。

SpringDataRedis针对Jedis提供了如下功能:

  1. 连接池自动管理,提供了一个高度封装的RedisTemplate类

  2. 针对Jedis客户端中大量api进行了归类封装,将同一类型操作封装为operation接口

     @SpringBootTest
     public class RedisTest {
         @Autowired
         private RedisTemplate redisTemplate;
     
         @Test
         public void redis() {
             redisTemplate.opsForValue().set("name", "张三");
             Object name = redisTemplate.opsForValue().get("name");
             System.out.println(name);
        }
     }
    • ValueOperations:简单K-V操作 、

    • SetOperations:set类型数据操作.

    • ZSetOperations:zset类型数据操作

    • HashOperations:针对map类型的数据操作

    • ListOperations:针对list类型的数据操作

  3. 提供了对key的“bound”(绑定)便捷化操作API,可以通过bound封装指定的key,然后进行一系列的操作而无须“显式”的再次指定Key,即BoundKeyOperations:

     @SpringBootTest
     public class RedisTest {
         @Autowired
         private RedisTemplate redisTemplate;
     
         @Test
         public void redis() {
             Object name = redisTemplate.boundValueOps("name").get();
             System.out.println(name);
        }
     }
    • BoundValueOperations:绑定 string 类型的 key  

    • BoundListOperations:绑定 list 类型的 key  

    • BoundHashOperations:绑定 hash 即 map 类型的 key  

    • BoundSetOperations:绑定 set 类型的 key  

    • BoundZSetOperations:绑定 zset 类型的 key

  4. 将事务操作封装,由容器控制。

  5. 针对数据的“序列化/反序列化”,提供了多种可选择策略(RedisSerializer)

2.RedisTemplate数据操作

通用方法

  1. 删除 key

     // 删除单个 key,返回布尔值
     redisTemplate.delete(K key);
     
     // 删除多个 key,返回删除的个数
     redisTemplate.delete(Collection<K> keys);
  2. 判断 key 是否存在

     // 返回布尔值
     redisTemplate.hasKey(key);
  3. key 有效时间

     // 指定有效时间
     redisTemplate.expire(key, time, TimeUnit.MINUTES);
     
     // 获取有效时间,返回值单位为秒
     redisTemplate.getExpire(key);

操作 string

  1. 添加数据

     // 通过 ValueOperations 设置值
     ValueOperations ops = redisTemplate.opsForValue();
     // 存入数据
     ops.set(key, value);
     // 设置过期时间
     ops.set(key, value, time, TimeUnit.SECONDS);
     
     // 通过 BoundValueOperations 设置值
     BoundValueOperations key = redisTemplate.boundValueOps(key);
     key.set(value);
     key.set(value, time, TimeUnit.SECONDS);
  2. 获取数据

     // 通过 ValueOperations 获取值
     redisTemplate.opsForValue().get(key);
     
     // 通过 BoundValueOperations 获取值
     redisTemplate.boundValueOps(key).get();

操作 list

  1. 添加数据

     // 通过 ValueOperations 设置值
     ListOperations opsList = redisTemplate.opsForList();
     opsList.leftPush(listKey, listLeftValue);
     opsList.rightPush(listKey, listRightValue);
     // 存入集合
     opsList.rightPushAll(list);
     opsList.leftPushAll(list);
     
  2. 获取数据

    // 获取集合中的数据
    redisTemplate.boundListOps(listKey).range(startIndex, endindex);

    // 根据索引获取数据
    redisTemplate.boundListOps(listKey).index(index);

    // 集合长度
    redisTemplate.boundListOps(listKey).size();
  3. 删除数据

    // 从左侧弹出一个元素并返回
    redisTemplate.boundListOps(listKey).leftPop();

    // 从右侧弹出一个元素并返回
    redisTemplate.boundListOps(listKey).rightPop();

    // 移出 N 个值为 value 的元素
    redisTemplate.boundListOps(listKey).remove(long, value);
  4. 修改数据

    // 根据索引修改数据
    redisTemplate.boundListOps(listKey).set(index, listLeftValue);

操作 hash

  1. 添加数据

    // 通过 BoundValueOperations 设置值
    BoundHashOperations hashKey = redisTemplate.boundHashOps(HashKey);
    hashKey.put(key, Vaue);
    // 添加一个集合
    hashKey.putAll(hashMap);

    // 通过 ValueOperations 设置值
    HashOperations hashOps = redisTemplate.opsForHash();
    hashOps.put(HashKey, key, Vaue);
  2. 获取数据

    // 获取所有小 key
    redisTemplate.boundHashOps(HashKey).keys();

    // 根据小 key 获取值
    redisTemplate.boundHashOps(HashKey)get(key);

    // 获取所有键值对集合
    redisTemplate.boundHashOps(HashKey).entries();
  3. 删除数据

    // 判断 hash 中是否存在小 key
    redisTemplate.boundHashOps(HashKey).hasKey(key);

    // 根据小 key 删除值
    redisTemplate.boundHashOps(HashKey).delete(key);

操作 Set

  1. 添加数据

    // 通过 BoundValueOperations 设置值
    redisTemplate.boundSetOps(setKey).add(setValue1, setValue2, setValue3);

    // 通过 ValueOperations 设置值
    redisTemplate.opsForSet().add(setKey, SetValue1, setValue2, setValue");
  2. 获取数据

    // 获取所有值
    redisTemplate.boundSetOps(setKey).members();

    // 获取 set 的长度
    redisTemplate.boundSetOps(setKey).size();
  3. 删除数据

    // 判断 set 中是否存在改值
    redisTemplate.boundSetOps(setKey).isMember(setValue);

    // 移出指定的值
    redisTemplate.boundSetOps(setKey).remove(setValue);

操作 zset

  1. 添加数据

    // 通过 BoundValueOperations 设置值
    redisTemplate.boundZSetOps(zSetKey).add(zSetVaule, score);

    // 通过 ValueOperations 设置值
    redisTemplate.opsForZSet().add(zSetKey, zSetVaule, score);
  2. 获取数据

    // 获取元素集合, 按照排名先后(从小到大)
    redisTemplate.boundZSetOps(zSetKey).range(key, startIndex, endIndex);

    // 获取指定值的分数(权重)
    redisTemplate.boundZSetOps(zSetKey).score(zSetVaule);

    // 获取 zset 长度
    redisTemplate.boundZSetOps(zSetKey).size();
  3. 修改分数

    // 修改指定元素的分数
    redisTemplate.boundZSetOps(zSetKey).incrementScore(zSetVaule, score);
  4. 删除数据

    // 删除指定元素
    redisTemplate.boundZSetOps(zSetKey).remove(zSetVaule);

    // 删除指定索引范围的元素
    redisTemplate.boundZSetOps(zSetKey).removeRange(strat, end);

    // 删除指定分数范围的元素
    redisTemplate.boundZSetOps(zSetKey).removeRangeByScorssse(strat, end);


3.SpringDataRedis两种使用方式

SpringDataRedis使用时主要有两种方式

  1. 缓存注解实现

  2. 工具类实现

SpringDataJpa在项目中使用

引入依赖包

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>

添加配置文件

# Redis数据库索引(默认为0)
spring.redis.database=0
# Redis服务器地址
spring.redis.host=localhost
# Redis服务器连接端口
spring.redis.port=6379
# Redis服务器连接密码(默认为空)
spring.redis.password=
# 连接池最大连接数(使用负值表示没有限制) 默认 8
spring.redis.lettuce.pool.max-active=8
# 连接池最大阻塞等待时间(使用负值表示没有限制) 默认 -1
spring.redis.lettuce.pool.max-wait=-1
# 连接池中的最大空闲连接 默认 8
spring.redis.lettuce.pool.max-idle=8
# 连接池中的最小空闲连接 默认 0
spring.redis.lettuce.pool.min-idle=0

创建Redis配置类用于生成Key

@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport{
@Bean
public KeyGenerator keyGenerator() {
return new KeyGenerator() {
@Override
public Object generate(Object target, Method method, Object... params) {
StringBuilder sb = new StringBuilder();
sb.append(target.getClass().getName());
sb.append(method.getName());
for (Object obj : params) {
sb.append(obj.toString());
}
return sb.toString();
}
};
}
}

注意我们使用了注解:@EnableCaching来开启缓存。

自动根据方法上的注解生成缓存

@RestController
public class UserController {
@Autowired
private UserService userService;
@RequestMapping("/getUser.json")
@Cacheable(value="user-key")
public User getUser() {
User user=userService.getUserById(1);
return user;
}
}
//数据库查询只执行一次、剩余访问会直接走Redis缓存

工具类

 @Component
 public class RedisUtil {
 
     @Autowired
     private RedisTemplate<Object, Object> redisTemplate;
 
     // =============================common============================
 
     /**
      * 添加字符串KEY
      *
      * @param key     字符串KEY
      * @param value   值 可以为对象
      * @param expire   过期时间
      * @param timeUnit TimeUnit中定义的时间单位
      */
     public void addKey(String key, Object value, long expire, TimeUnit timeUnit) {
         this.redisTemplate.opsForValue().set(key, value, expire, timeUnit);
    }
 
     /**
      * 指定缓存失效时间
      *
      * @param key 键
      * @param time 时间(秒)
      * @return
      */
     public boolean expire(String key, long time) {
         try {
             if (time > 0) {
                 redisTemplate.expire(key, time, TimeUnit.SECONDS);
            }
             return true;
        } catch (Exception e) {
             e.printStackTrace();
             return false;
        }
    }
 
     /**
      * 根据KEY获取VALUE
      *
      * @param key
      * @return value
      */
     public Object getValue(String key) {
         return this.redisTemplate.opsForValue().get(key);
    }
 
 
     /**
      * 根据key 获取过期时间
      *
      * @param key 键 不能为null
      * @return 时间(秒) 返回0代表为永久有效
      */
     public long getExpire(String key) {
         return redisTemplate.getExpire(key, TimeUnit.SECONDS);
    }
 
     /**
      * 判断key是否存在
      *
      * @param key 键
      * @return true 存在 false不存在
      */
     public boolean hasKey(String key) {
         try {
             return redisTemplate.hasKey(key);
        } catch (Exception e) {
             e.printStackTrace();
             return false;
        }
    }
 
     /**
      * 删除缓存
      *
      * @param key 可以传一个值 或多个
      */
     @SuppressWarnings("unchecked")
     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=============================
 
     /**
      * 普通缓存获取
      *
      * @param key 键
      * @return 值
      */
     public Object get(String key) {
         return key == null ? null : redisTemplate.opsForValue().get(key);
    }
 
     /**
      * 普通缓存放入
      *
      * @param key   键
      * @param value 值
      * @return true成功 false失败
      */
     public boolean set(String key, Object value) {
         try {
             redisTemplate.opsForValue().set(key, value);
             return true;
        } catch (Exception e) {
             e.printStackTrace();
             return false;
        }
 
    }
 
     /**
      * 普通缓存放入并设置时间
      *
      * @param key   键
      * @param value 值
      * @param time 时间(秒) time要大于0 如果time小于等于0 将设置无限期
      * @return true成功 false 失败
      */
     public boolean set(String key, Object value, long time) {
         try {
             if (time > 0) {
                 redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
            } else {
                 set(key, value);
            }
             return true;
        } catch (Exception e) {
             e.printStackTrace();
             return false;
        }
    }
 
     /**
      * 递增
      *
      * @param key   键
      * @param delta 要增加几(大于0)
      * @return
      */
     public long incr(String key, long delta) {
         if (delta < 0) {
             throw new RuntimeException("递增因子必须大于0");
        }
         return redisTemplate.opsForValue().increment(key, delta);
    }
 
     /**
      * 递减
      *
      * @param key   键
      * @param delta 要减少几(小于0)
      * @return
      */
     public long decr(String key, long delta) {
         if (delta < 0) {
             throw new RuntimeException("递减因子必须大于0");
        }
         return redisTemplate.opsForValue().increment(key, -delta);
    }
 
     // ================================Map=================================
 
     /**
      * HashGet
      *
      * @param key 键 不能为null
      * @param item 项 不能为null
      * @return 值
      */
     public Object hget(String key, String item) {
         return redisTemplate.opsForHash().get(key, item);
    }
 
     /**
      * 获取hashKey对应的所有键值
      *
      * @param key 键
      * @return 对应的多个键值
      */
     public Map<Object, Object> hmget(String key) {
         return redisTemplate.opsForHash().entries(key);
    }
 
     /**
      * HashSet
      *
      * @param key 键
      * @param map 对应多个键值
      * @return true 成功 false 失败
      */
     public boolean hmset(String key, Map<String, Object> map) {
         try {
             redisTemplate.opsForHash().putAll(key, map);
             return true;
        } catch (Exception e) {
             e.printStackTrace();
             return false;
        }
    }
 
     /**
      * HashSet 并设置时间
      *
      * @param key 键
      * @param map 对应多个键值
      * @param time 时间(秒)
      * @return true成功 false失败
      */
     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 (Exception e) {
             e.printStackTrace();
             return false;
        }
    }
 
     /**
      * 向一张hash表中放入数据,如果不存在将创建
      *
      * @param key   键
      * @param item 项
      * @param value 值
      * @return true 成功 false失败
      */
     public boolean hset(String key, String item, Object value) {
         try {
             redisTemplate.opsForHash().put(key, item, value);
             return true;
        } catch (Exception e) {
             e.printStackTrace();
             return false;
        }
    }
 
     /**
      * 向一张hash表中放入数据,如果不存在将创建
      *
      * @param key   键
      * @param item 项
      * @param value 值
      * @param time 时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间
      * @return true 成功 false失败
      */
     public boolean hset(String key, String item, Object value, long time) {
         try {
             redisTemplate.opsForHash().put(key, item, value);
             if (time > 0) {
                 expire(key, time);
            }
             return true;
        } catch (Exception e) {
             e.printStackTrace();
             return false;
        }
    }
 
     /**
      * 删除hash表中的值
      *
      * @param key 键 不能为null
      * @param item 项 可以使多个 不能为null
      */
     public void hdel(String key, Object... item) {
         redisTemplate.opsForHash().delete(key, item);
    }
 
     /**
      * 判断hash表中是否有该项的值
      *
      * @param key 键 不能为null
      * @param item 项 不能为null
      * @return true 存在 false不存在
      */
     public boolean hHasKey(String key, String item) {
         return redisTemplate.opsForHash().hasKey(key, item);
    }
 
     /**
      * hash递增 如果不存在,就会创建一个 并把新增后的值返回
      *
      * @param key 键
      * @param item 项
      * @param by   要增加几(大于0)
      * @return
      */
     public double hincr(String key, String item, double by) {
         return redisTemplate.opsForHash().increment(key, item, by);
    }
 
     /**
      * hash递减
      *
      * @param key 键
      * @param item 项
      * @param by   要减少记(小于0)
      * @return
      */
     public double hdecr(String key, String item, double by) {
         return redisTemplate.opsForHash().increment(key, item, -by);
    }
 
     // ============================set=============================
 
     /**
      * 根据key获取Set中的所有值
      *
      * @param key 键
      * @return
      */
     public Set<Object> sGet(String key) {
         try {
             return redisTemplate.opsForSet().members(key);
        } catch (Exception e) {
             e.printStackTrace();
             return null;
        }
    }
 
     /**
      * 根据value从一个set中查询,是否存在
      *
      * @param key   键
      * @param value 值
      * @return true 存在 false不存在
      */
     public boolean sHasKey(String key, Object value) {
         try {
             return redisTemplate.opsForSet().isMember(key, value);
        } catch (Exception e) {
             e.printStackTrace();
             return false;
        }
    }
 
     /**
      * 将数据放入set缓存
      *
      * @param key   键
      * @param values 值 可以是多个
      * @return 成功个数
      */
     public long sSet(String key, Object... values) {
         try {
             return redisTemplate.opsForSet().add(key, values);
        } catch (Exception e) {
             e.printStackTrace();
             return 0;
        }
    }
 
     /**
      * 将set数据放入缓存
      *
      * @param key   键
      * @param time   时间(秒)
      * @param values 值 可以是多个
      * @return 成功个数
      */
     public long sSetAndTime(String key, long time, Object... values) {
         try {
             Long count = redisTemplate.opsForSet().add(key, values);
             if (time > 0)
                 expire(key, time);
             return count;
        } catch (Exception e) {
             e.printStackTrace();
             return 0;
        }
    }
 
     /**
      * 获取set缓存的长度
      *
      * @param key 键
      * @return
      */
     public long sGetSetSize(String key) {
         try {
             return redisTemplate.opsForSet().size(key);
        } catch (Exception e) {
             e.printStackTrace();
             return 0;
        }
    }
 
     /**
      * 移除值为value的
      *
      * @param key   键
      * @param values 值 可以是多个
      * @return 移除的个数
      */
     public long setRemove(String key, Object... values) {
         try {
             Long count = redisTemplate.opsForSet().remove(key, values);
             return count;
        } catch (Exception e) {
             e.printStackTrace();
             return 0;
        }
    }
     // ===============================list=================================
 
     /**
      * 获取list缓存的内容
      *
      * @param key   键
      * @param start 开始
      * @param end   结束 0 到 -1代表所有值
      * @return
      */
     public List<Object> lGet(String key, long start, long end) {
         try {
             return redisTemplate.opsForList().range(key, start, end);
        } catch (Exception e) {
             e.printStackTrace();
             return null;
        }
    }
 
     /**
      * 获取list缓存的长度
      *
      * @param key 键
      * @return
      */
     public long lGetListSize(String key) {
         try {
             return redisTemplate.opsForList().size(key);
        } catch (Exception e) {
             e.printStackTrace();
             return 0;
        }
    }
 
     /**
      * 通过索引 获取list中的值
      *
      * @param key   键
      * @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推
      * @return
      */
     public Object lGetIndex(String key, long index) {
         try {
             return redisTemplate.opsForList().index(key, index);
        } catch (Exception e) {
             e.printStackTrace();
             return null;
        }
    }
 
     /**
      * 将list放入缓存
      *
      * @param key   键
      * @param value 值
      * @return
      */
     public boolean lSet(String key, Object value) {
         try {
             redisTemplate.opsForList().rightPush(key, value);
             return true;
        } catch (Exception e) {
             e.printStackTrace();
             return false;
        }
    }
 
     /**
      * 将list放入缓存
      *
      * @param key   键
      * @param value 值
      * @param time 时间(秒)
      * @return
      */
     public boolean lSet(String key, Object value, long time) {
         try {
             redisTemplate.opsForList().rightPush(key, value);
             if (time > 0)
                 expire(key, time);
             return true;
        } catch (Exception e) {
             e.printStackTrace();
             return false;
        }
    }
 
     /**
      * 将list放入缓存
      *
      * @param key   键
      * @param value 值
      * @return
      */
     public boolean lSet(String key, List<Object> value) {
         try {
             redisTemplate.opsForList().rightPushAll(key, value);
             return true;
        } catch (Exception e) {
             e.printStackTrace();
             return false;
        }
    }
 
     /**
      * 将list放入缓存
      *
      * @param key   键
      * @param value 值
      * @param time 时间(秒)
      * @return
      */
     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 (Exception e) {
             e.printStackTrace();
             return false;
        }
    }
 
     /**
      * 根据索引修改list中的某条数据
      *
      * @param key   键
      * @param index 索引
      * @param value 值
      * @return
      */
     public boolean lUpdateIndex(String key, long index, Object value) {
         try {
             redisTemplate.opsForList().set(key, index, value);
             return true;
        } catch (Exception e) {
             e.printStackTrace();
             return false;
        }
    }
 
     /**
      * 移除N个值为value
      *
      * @param key   键
      * @param count 移除多少个
      * @param value 值
      * @return 移除的个数
      */
     public long lRemove(String key, long count, Object value) {
         try {
             Long remove = redisTemplate.opsForList().remove(key, count, value);
             return remove;
        } catch (Exception e) {
             e.printStackTrace();
             return 0;
        }
    }
 }



博观而约取,厚积而薄发!



--END--