Spring Boot Data(数据) Redis 中提供了 RedisTemplate 和 StringRedisTemplate;
StringRedisTemplate 是 RedisTemplate 的子类,两个方法基本一致,不同之处在于 操作的数据类型不同:
RedisTemplate 两个泛型都是 Object,意味着存储的 key 和 value 都可以是一个对象StringRedisTemplate 两个泛型都是 String,意味着存储的 的 key 和 value 都只能是字符串。注:使用 RedisTemplate 默认是将对象序列化到 Redis 中,所以 放入的对象必须实现对象序列化接口。
注:两者的 数据是不共通的;也就是说 StringRedisTemplate 只能管理 StringRedisTemplate 里面的数据,RedisTemplate 只能管理 RedisTemplate 中的数据。
API 是学不完的,掌握一些基本操作,其他操作有需要再查询即可!
StringRedisTemplate.opsForValue(); // 操作字符串 StringRedisTemplate.opsForHash(); // 操作hash StringRedisTemplate.opsForList(); // 操作list StringRedisTemplate.opsForSet(); // 操作set StringRedisTemplate.opsForZSet(); // 操作有序set通过@Autowired注解的方式注入 StringRedisTemplate 对象:
@Autowired private StringRedisTemplate stringRedisTemplate; // key, value 都是字符串删除一个 key:
stringRedisTemplate.delete("name"); // 删除一个key删除当前 redis 库中所有键值对:
// 删除当前redis库中所有键值对 Set<String> keys = stringRedisTemplate.keys("*"); // 查询出所有的键 stringRedisTemplate.delete(keys);判断某个 key 是否存在,判断 key 所对应值的类型:
Boolean hasKey = stringRedisTemplate.hasKey("name"); // 判断某个key是否存在 DataType type = stringRedisTemplate.type("name"); // 判断key对应的值的类型获取 key 超时时间(-1 永不超时,-2 key不存在,>=0 过期时间)
Long expire = stringRedisTemplate.getExpire("name");在 redis 中随机获取一个 key:
String randomKey = stringRedisTemplate.randomKey();修改 key 的名字,要求 key 必须存在,不存在则抛出异常:
stringRedisTemplate.rename("name", "newname"); // stringRedisTemplate.renameIfAbsent("age", "newname");将指定 key 移动到 指定库:
stringRedisTemplate.move("newname", 1);所有字符串的操作都是通过 StringRedisTemplate.opsForValue(); 实现。
设置一个 key value:
stringRedisTemplate.opsForValue().set("name", "振宇"); // set 用来设置一个key value获取一个 key 对应 value:
String value = stringRedisTemplate.opsForValue().get("name");设置一个 key 超时时间:
// key:code value:2537 超时时间:120s stringRedisTemplate.opsForValue().set("code", "2537", 120, TimeUnit.SECONDS);往指定键的值后面 追加 字符串:
stringRedisTemplate.opsForValue().append("name", "他是一个好人!");所有 List 的操作都是通过 StringRedisTemplate.opsForList(); 实现。
从左边往列表中放入一个元素:
stringRedisTemplate.opsForList().leftPush("lists", "振宇");从左边往列表中放入多个元素(两种方法):
stringRedisTemplate.opsForList().leftPushAll("lists", "张三", "李四", "王五"); List<String> names = new ArrayList<>(); names.add("xiaoming"); names.add("xiaosan"); stringRedisTemplate.opsForList().leftPushAll("lists", names);遍历整个 List:
List<String> stringList = stringRedisTemplate.opsForList().range("lists", 0, -1);// 遍历list stringList.forEach(v -> System.out.println("value = " + v));保留截取的指定区间的 List:
stringRedisTemplate.opsForList().trim("lists", 1, 3);所有 Set 的操作都是通过 StringRedisTemplate.opsForSet(); 实现。
创建 Set 并放入多个元素:
stringRedisTemplate.opsForSet().add("sets", "张三", "张三", "李四", "振宇"); // 创建set 并放入多个元素查看 Set 中所有成员:
Set<String> sets = stringRedisTemplate.opsForSet().members("sets"); sets.forEach(value -> System.out.println("value = " + value));获取 Set 中元素个数:
Long size = stringRedisTemplate.opsForSet().size("sets");所有 ZSet 的操作都是通过 StringRedisTemplate.opsForZSet(); 实现。
创建 ZSet 并放入元素:
stringRedisTemplate.opsForZSet().add("zsets", "小黑", 20);指定范围进行查询:
// 遍历所有元素 Set<String> zsets = stringRedisTemplate.opsForZSet().range("zsets", 0, -1); zsets.forEach(value-> System.out.println(value));获取指定元素以及分数(可以指定分数范围):
// 获取分数范围在 0 -1000 之间的元素 并排序 Set<ZSetOperations.TypedTuple<String>> zsets1 = stringRedisTemplate.opsForZSet().rangeByScoreWithScores("zsets", 0, 1000); zsets1.forEach(typedTuple ->{ System.out.println("value = " + typedTuple.getValue() + ", score = " + typedTuple.getScore()); });所有 Hash 的操作都是通过 StringRedisTemplate.opsForHash(); 实现。
往指定 Hash 中放入一个 key,value:
stringRedisTemplate.opsForHash().put("maps", "name", "zhangsan");往指定 Hash 中放入多个 key,value:
Map<String, String> map = new HashMap<>(); map.put("age", "12"); map.put("bir", "2012-12-12"); stringRedisTemplate.opsForHash().putAll("maps", map); // 放入多个key, value获取指定 Hash 中某个 key 的 value:
String value = (String) stringRedisTemplate.opsForHash().get("maps", "name");获取指定 Hash 中多个 key 的 value:
List<Object> values = stringRedisTemplate.opsForHash().multiGet("maps", Arrays.asList("name", "age")); values.forEach(value -> System.out.println(value));获取指定 Hash 中所有 key,获取所有 value:
Set<Object> keys = stringRedisTemplate.opsForHash().keys("maps"); // 获取所有keys List<Object> vals = stringRedisTemplate.opsForHash().values("maps"); // 获取所有valuesSpring Data 为了方便我们对 redis 进行更友好的操作,提供了 bound api 简化操作。
如果日后对某一个 key 的操作极其频繁,可以将这个 key 绑定到对应 redistemplate 中,可以简化操作。
boundValueOps 用来对 String 值绑定 keyboundListOps 用来对 List 值绑定 keyboundSetOps 用来对 Set 值绑定 keyboundZSetOps 用来对 ZSet 值绑定 keyboundHashOps 用来对 Hash 值绑定 key原本代码可能需要这么写:
stringRedisTemplate.opsForValue().set("name", "zhangsan"); stringRedisTemplate.opsForValue().append("name", "是一个好人"); String s = stringRedisTemplate.opsForValue().get("name"); System.out.println(s);绑定后只需要这么写:
BoundValueOperations<String, String> nameValueOperations = stringRedisTemplate.boundValueOps("name"); nameValueOperations.set("zhangsan"); nameValueOperations.append("是一个好人"); String name = nameValueOperations.get();对 List 进行绑定:
BoundListOperations<String, String> listsOperations = stringRedisTemplate.boundListOps("lists"); listsOperations.leftPushAll("张三", "李四", "小陈"); List<String> lists = listsOperations.range(0, -1); lists.forEach(list-> System.out.println(list));redis 中每个数据类型都可以进行绑定,与上面同理。
RedisTemplate 的用法和 StringRedisTemplate 基本一样,我们关注他们的不同之处!
RedisTemplate 和 StringRedisTemplate 的区别主要在于他们使用的序列化类:
RedisTemplate 使用的是 JdkSerializationRedisSerializer,存入数据时,会将数据先序列化成字节数组,然后再存入 Redis 数据库。;StringRedisTemplate 使用的是 StringRedisSerializer;通过@Autowired注解的方式注入 RedisTemplate 对象:
@Autowired private RedisTemplate redisTemplate; //存储对象想要存入 redis 的对象必须实现序列化接口:
@Data @AllArgsConstructor @NoArgsConstructor @Accessors(chain = true) public class User implements Serializable { // 实现序列化接口 private String id; private String name; private Integer age; private Date bir; }往 redis 中存入一个 User 对象:
redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer()); // 指定值使用对象序列化 // 往redis中存入一个User对象 redisTemplate.opsForValue().set("user", new User("21", "小黑", 23, new Date())); // 根据值获取存入的User对象 User user = (User) redisTemplate.opsForValue().get("user"); System.out.println(user);需要注意的是,如果通过 redis 客户端查看其中的数据,无法正常显示 key 名,如下图:
RedisTemplate 正常往 redis 中存入 String 数据与 StringRedisTemplate 用法几乎一样,但是如果存放的是 String 类型数据则更推荐 StringRedisTemplate 而不是 RedisTemplate
redisTemplate.opsForList().leftPushAll("lists", "hello", "world"); List lists = redisTemplate.opsForList().range("lists", 0, -1); lists.forEach(list -> System.out.println(list));RedisTemplate 和 StringRedisTemplate 的数据是不相通的!
1、StringRedisTemplate 往 redis 中存入一个 String 类型的值,分别尝试获取值:
RedisTemplate 无法获取到;StringRedisTemplate 可以获取到; stringRedisTemplate.opsForValue().set("name", "zhenyu"); Object name1 = redisTemplate.opsForValue().get("name"); System.out.println(name1); // null String name2 = stringRedisTemplate.opsForValue().get("name"); System.out.println(name2); // zhenyu注:如果是在客户端中操作,视为使用 StringRedisTemplate。
2、RedisBuilder 往 redis 中存入一个 User 对象,分别尝试获取值:
RedisTemplate 可以获取到;StringRedisTemplate 无法获取到; redisTemplate.opsForValue().set("user", new User("21", "zhenyu", 23, new Date())); User user1 = (User) redisTemplate.opsForValue().get("user"); System.out.println(user1); // User(id=21, name=zhenyu, age=23, bir=Sat Jul 04 10:17:12 CST 2020) String user2 = stringRedisTemplate.opsForValue().get("user"); System.out.println(user2); // null3、RedisTemplate 往 redis 中存入一个 String 类型的值,分别尝试获取值:
RedisTemplate 可以获取到;StringRedisTemplate 无法获取到; redisTemplate.opsForValue().set("name", "hello"); Object name1 = redisTemplate.opsForValue().get("name"); System.out.println(name1); // hello String name2 = stringRedisTemplate.opsForValue().get("name"); System.out.println(name2); // null上面我们学习的只是 StringRedisTemplate 与 RedisTemplate 的基础操作,Redis 真正实现的功能都是建立在这些基础上的,企业中 Redis 的应用场景主要有:
利用 Redis 中字符串类型完成 手机验证码存储 的实现;利用 Redis 中字符串类型完成 具有失效性业务功能,例如淘宝的订单失效时间…利用 Redis 实现分布式集群系统中 Session共享;利用 Redis 中 ZSet 类型(可排序的 Set 类型)实现 排行榜功能,sales(zset) [商品id,商品销量]…利用 Redis 实现 分布式缓存;利用 Redis 存储认证之后 token 信息,例如微信小程序开发中获取的令牌可能会超时…利用 Redis 解决分布式集群系统中分布式锁问题; …