Java 操作 Redis
- Spring Boot Redis Template
- Redisson
1、redisTemplate 是基于某个具体实现的再封装,比如说 springBoot1.x 时,具体实现是 jedis;而到了 springBoot2.x 时,具体实现变成了 lettuce。封装的好处就是隐藏了具体的实现,使调用更简单,但是有人测试过 jedis 效率要 10-30 倍的高于 redisTemplate 的执行效率,所以单从执行效率上来讲,jedis 完爆 redisTemplate。redisTemplate 的好处就是基于 springBoot 自动装配的原理,使得整合 redis 时比较简单。
2、jedis 作为老牌的 redis 客户端,采用同步阻塞式 IO,采用线程池时是线程安全的。优点是简单、灵活、api 全面,缺点是某些 redis 高级功能需要自己封装。
3、lettuce 作为新式的 redis 客户端,基于 netty 采用异步非阻塞式 IO,是线程安全的,优点是提供了很多 redis 高级功能,例如集群、哨兵、管道等,缺点是 api 抽象,学习成本高。lettuce 好是好,但是 jedis 比他生得早。
4、redission 作为 redis 的分布式客户端,同样基于 netty 采用异步非阻塞式 IO,是线程安全的,优点是提供了很多 redis 的分布式操作和高级功能,缺点是 api 抽象,学习成本高。
中文文档: https://github.com/redisson/redisson/wiki
综上所述:单机并发量低时优先选择 jedis,分布式高并发时优先选择 redission。
Spring-Boot-操作-Redis,三种方案全解析! - 江南一点雨 - 博客园
一、SpringDataRedis 简介
1、Redis
redis 是一款开源的 Key-Value 数据库,运行在内存中,由 C 语言编写。企业开发通常采用 Redis 来实现缓存。同类的产品还有 memcache 、memcached 等。
2、Jedis
Jedis 是 Redis 官方推出的一款面向 Java 的客户端,提供了很多接口供 Java 语言调用。可以在 Redis 官网下载,当然还有一些开源爱好者提供的客户端,如 Jredis、SRP 等等,推荐使用 Jedis。
1) pom.xml 引入 Jedis 依赖
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.2.0</version>
</dependency>2) Jedis 简单使用
package com.atguigu.jedis;
import redis.clients.jedis.Jedis;
public class Demo01 {
public static void main(String[] args) {
Jedis jedis = new Jedis("192.168.137.3",6379);
String pong = jedis.ping();
System.out.println("连接成功:"+pong);
jedis.close();
}
}3、Spring Data Redis
Spring-data-redis 是 spring 大家族的一部分,提供了在 srping 应用中通过简单的配置访问 redis 服务,对 reids 底层开发包(Jedis, JRedis, and RJC)进行了高度封装,RedisTemplate 提供了 redis 各种操作、异常处理及序列化,支持发布订阅,并对 spring 3.1 cache 进行了实现。
spring-data-redis 针对 jedis 提供了如下功能:
- 连接池自动管理,提供了一个高度封装的“RedisTemplate”类
- 针对 jedis 客户端中大量 api 进行了归类封装,将同一类型操作封装为 operation 接口
- ValueOperations:简单 K-V 操作
- SetOperations:set 类型数据操作
- ZSetOperations:zset 类型数据操作
- HashOperations:针对 map 类型的数据操作
- ListOperations:针对 list 类型的数据操作
- 提供了对 key 的“bound”(绑定)便捷化操作 API,可以通过 bound 封装指定的 key,然后进行一系列的操作而无须“显式”的再次指定 Key,即 BoundKeyOperations:
- BoundValueOperations
- BoundSetOperations
- BoundListOperations
- BoundSetOperations
- BoundHashOperations
- 将事务操作封装,有容器控制。
- 针对数据的“序列化/反序列化”,提供了多种可选择策略(RedisSerializer)
JdkSerializationRedisSerializer:POJO 对象的存取场景,使用 JDK 本身序列化机制,将 pojo 类通过 ObjectInputStream/ObjectOutputStream 进行序列化操作,最终 redis-server 中将存储字节序列。是目前最常用的序列化策略。
StringRedisSerializer:Key 或者 value 为字符串的场景,根据指定的 charset 对数据的字节序列编码成 string,是“new String(bytes, charset)”和“string.getBytes(charset)”的直接封装。是最轻量级和高效的策略。
JacksonJsonRedisSerializer:jackson-json 工具提供了 javabean 与 json 之间的转换能力,可以将 pojo 实例序列化成 json 格式存储在 redis 中,也可以将 json 格式的数据转换成 pojo 实例。因为 jackson 工具在序列化和反序列化时,需要明确指定 Class 类型,因此此策略封装起来稍微复杂。【需要 jackson-mapper-asl 工具支持】
二、RedisTemplate 中 API 使用
1、pom.xml 依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>2、配置文件
# Redis服务器连接端口
spring.redis.port=6379
# Redis服务器地址
spring.redis.host=127.0.0.1
# Redis数据库索引(默认为0)
spring.redis.database=0
# Redis服务器连接密码(默认为空)
spring.redis.password=
# 连接池最大连接数(使用负值表示没有限制)
spring.redis.jedis.pool.max-active=8
# 连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.jedis.pool.max-wait=-1ms
# 连接池中的最大空闲连接
spring.redis.jedis.pool.max-idle=8
# 连接池中的最小空闲连接
spring.redis.jedis.pool.min-idle=0
# 连接超时时间(毫秒)
spring.redis.timeout=5000ms3、RedisTemplate 的直接方法
默认情况下的模板只能支持 RedisTemplate<String, String>,也就是只能存入字符串,所以自定义模板很有必要。添加配置类 RedisCacheConfig.java
@Configuration
@AutoConfigureAfter(RedisAutoConfiguration.class)
public class RedisCacheConfig {
@Bean
public RedisTemplate<String, Serializable> redisCacheTemplate(LettuceConnectionFactory connectionFactory) {
RedisTemplate<String, Serializable> template = new RedisTemplate<>();
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
template.setConnectionFactory(connectionFactory);
return template;
}
}
@Data
public class User implements Serializable{
private static final long serialVersionUID = 662692455422902539L;
private Integer id;
private String name;
private Integer age;
}
@Autowired
private RedisTemplate<String, Serializable> redisCacheTemplate;
@RequestMapping("/test")
public void test() {
redisCacheTemplate.opsForValue().set("userkey", new User(1, "张三", 25));
User user = (User) redisCacheTemplate.opsForValue().get("userkey");
logger.info("当前获取对象:{}", user.toString());
}首先使用@Autowired 注入 RedisTemplate(后面直接使用,就不特殊说明)
@Autowired
private RedisTemplate redisTemplate;1、删除单个 key
public void delete(String key){
redisTemplate.delete(key);
}2、删除多个 key
public void deleteKey (String ...keys){
redisTemplate.delete(keys);
}
3、指定 key 的失效时间
// 指定key的失效时间
public void expire(String key,long time){
redisTemplate.expire(key,time,TimeUnit.MINUTES);
}
4、根据 key 获取过期时间
// 根据key获取过期时间
public long getExpire(String key){
Long expire = redisTemplate.getExpire(key);
return expire;
}5、判断 key 是否存在
// 判断key是否存在
public boolean hasKey(String key){
return redisTemplate.hasKey(key);
}4、String 类型相关操作
1)、添加缓存
//1、通过redisTemplate设置值
redisTemplate.boundValueOps("StringKey").set("StringValue");
redisTemplate.boundValueOps("StringKey").set("StringValue",1, TimeUnit.MINUTES);
//2、通过BoundValueOperations设置值
BoundValueOperations stringKey = redisTemplate.boundValueOps("StringKey");
stringKey.set("StringVaule");
stringKey.set("StringValue",1, TimeUnit.MINUTES);
//3、通过ValueOperations设置值
ValueOperations ops = redisTemplate.opsForValue();
ops.set("StringKey", "StringVaule");
ops.set("StringValue","StringVaule",1, TimeUnit.MINUTES);2)、设置过期时间(单独设置)
redisTemplate.boundValueOps("StringKey").expire(1,TimeUnit.MINUTES);
redisTemplate.expire("StringKey",1,TimeUnit.MINUTES);3)、获取缓存值
//1、通过redisTemplate设置值
String str1 = (String) redisTemplate.boundValueOps("StringKey").get();
//2、通过BoundValueOperations获取值
BoundValueOperations stringKey = redisTemplate.boundValueOps("StringKey");
String str2 = (String) stringKey.get();
//3、通过ValueOperations获取值
ValueOperations ops = redisTemplate.opsForValue();
String str3 = (String) ops.get("StringKey");4)、删除 key
Boolean result = redisTemplate.delete("StringKey");5)、顺序递增
redisTemplate.boundValueOps("StringKey").increment(3L);6)、顺序递减
redisTemplate.boundValueOps("StringKey").increment(-3L);5、Hash 类型相关操作
1)、添加缓存
//1、通过redisTemplate设置值
redisTemplate.boundHashOps("HashKey").put("SmallKey", "HashVaue");
//2、通过BoundValueOperations设置值
BoundHashOperations hashKey = redisTemplate.boundHashOps("HashKey");
hashKey.put("SmallKey", "HashVaue");
//3、通过ValueOperations设置值
HashOperations hashOps = redisTemplate.opsForHash();
hashOps.put("HashKey", "SmallKey", "HashVaue");2)、设置过期时间(单独设置)
redisTemplate.boundValueOps("HashKey").expire(1,TimeUnit.MINUTES);
redisTemplate.expire("HashKey",1,TimeUnit.MINUTES);3)、添加一个 Map 集合
HashMap<String, String> hashMap = new HashMap<>();
redisTemplate.boundHashOps("HashKey").putAll(hashMap );4)、设置过期时间(单独设置)
redisTemplate.boundValueOps("HashKey").expire(1,TimeUnit.MINUTES);
redisTemplate.expire("HashKey",1,TimeUnit.MINUTES);5)、提取所有的小 key
//1、通过redisTemplate获取值
Set keys1 = redisTemplate.boundHashOps("HashKey").keys();
//2、通过BoundValueOperations获取值
BoundHashOperations hashKey = redisTemplate.boundHashOps("HashKey");
Set keys2 = hashKey.keys();
//3、通过ValueOperations获取值
HashOperations hashOps = redisTemplate.opsForHash();
Set keys3 = hashOps.keys("HashKey");6)、提取所有的 value 值
//1、通过redisTemplate获取值
List values1 = redisTemplate.boundHashOps("HashKey").values();
//2、通过BoundValueOperations获取值
BoundHashOperations hashKey = redisTemplate.boundHashOps("HashKey");
List values2 = hashKey.values();
//3、通过ValueOperations获取值
HashOperations hashOps = redisTemplate.opsForHash();
List values3 = hashOps.values("HashKey");7)、根据 key 提取 value 值
//1、通过redisTemplate获取
String value1 = (String) redisTemplate.boundHashOps("HashKey").get("SmallKey");
//2、通过BoundValueOperations获取值
BoundHashOperations hashKey = redisTemplate.boundHashOps("HashKey");
String value2 = (String) hashKey.get("SmallKey");
//3、通过ValueOperations获取值
HashOperations hashOps = redisTemplate.opsForHash();
String value3 = (String) hashOps.get("HashKey", "SmallKey");8)、获取所有的键值对集合
//1、通过redisTemplate获取
Map entries = redisTemplate.boundHashOps("HashKey").entries();
//2、通过BoundValueOperations获取值
BoundHashOperations hashKey = redisTemplate.boundHashOps("HashKey");
Map entries1 = hashKey.entries();
//3、通过ValueOperations获取值
HashOperations hashOps = redisTemplate.opsForHash();
Map entries2 = hashOps.entries("HashKey");9)、删除
//删除小key
redisTemplate.boundHashOps("HashKey").delete("SmallKey");
//删除大key
redisTemplate.delete("HashKey");10)、判断 Hash 中是否含有该值
Boolean isEmpty = redisTemplate.boundHashOps("HashKey").hasKey("SmallKey");6、Set 类型相关操作
1)、添加 Set 缓存(值可以是一个,也可是多个)(2/3 是 1 的递进值)
//1、通过redisTemplate设置值
redisTemplate.boundSetOps("setKey").add("setValue1", "setValue2", "setValue3");
//2、通过BoundValueOperations设置值
BoundSetOperations setKey = redisTemplate.boundSetOps("setKey");
setKey.add("setValue1", "setValue2", "setValue3");
//3、通过ValueOperations设置值
SetOperations setOps = redisTemplate.opsForSet();
setOps.add("setKey", "SetValue1", "setValue2", "setValue3");2)、设置过期时间(单独设置)
redisTemplate.boundValueOps("setKey").expire(1,TimeUnit.MINUTES);
redisTemplate.expire("setKey",1,TimeUnit.MINUTES);3)、根据 key 获取 Set 中的所有值
//1、通过redisTemplate获取值
Set set1 = redisTemplate.boundSetOps("setKey").members();
//2、通过BoundValueOperations获取值
BoundSetOperations setKey = redisTemplate.boundSetOps("setKey");
Set set2 = setKey.members();
//3、通过ValueOperations获取值
SetOperations setOps = redisTemplate.opsForSet();
Set set3 = setOps.members("setKey");4)、根据 value 从一个 set 中查询,是否存在
Boolean isEmpty = redisTemplate.boundSetOps("setKey").isMember("setValue2");5)、获取 Set 缓存的长度
Long size = redisTemplate.boundSetOps("setKey").size();6)、移除指定的元素
Long result1 = redisTemplate.boundSetOps("setKey").remove("setValue1");7)、移除指定的 key
Boolean result2 = redisTemplate.delete("setKey");7、 LIST 类型相关操作
1)、添加缓存
//1、通过redisTemplate设置值
redisTemplate.boundListOps("listKey").leftPush("listLeftValue1");
redisTemplate.boundListOps("listKey").rightPush("listRightValue2");
//2、通过BoundValueOperations设置值
BoundListOperations listKey = redisTemplate.boundListOps("listKey");
listKey.leftPush("listLeftValue3");
listKey.rightPush("listRightValue4");
//3、通过ValueOperations设置值
ListOperations opsList = redisTemplate.opsForList();
opsList.leftPush("listKey", "listLeftValue5");
opsList.rightPush("listKey", "listRightValue6");2)、将 List 放入缓存
ArrayList<String> list = new ArrayList<>();
redisTemplate.boundListOps("listKey").rightPushAll(list);
redisTemplate.boundListOps("listKey").leftPushAll(list);3)、设置过期时间(单独设置)
redisTemplate.boundValueOps("listKey").expire(1,TimeUnit.MINUTES);
redisTemplate.expire("listKey",1,TimeUnit.MINUTES);4)、获取 List 缓存全部内容(起始索引,结束索引)
List listKey1 = redisTemplate.boundListOps("listKey").range(0, 10);5)、从左或从右弹出一个元素
String listKey2 = (String) redisTemplate.boundListOps("listKey").leftPop(); //从左侧弹出一个元素
String listKey3 = (String) redisTemplate.boundListOps("listKey").rightPop(); //从右侧弹出一个元素6)、根据索引查询元素
String listKey4 = (String) redisTemplate.boundListOps("listKey").index(1);7)、获取 List 缓存的长度
Long size = redisTemplate.boundListOps("listKey").size();8)、根据索引修改 List 中的某条数据(key,索引,值)
redisTemplate.boundListOps("listKey").set(3L,"listLeftValue3");9)、移除 N 个值为 value(key,移除个数,值)
redisTemplate.boundListOps("listKey").remove(3L,"value");8、Zset 类型的相关操作
1)、向集合中插入元素,并设置分数
//1、通过redisTemplate设置值
redisTemplate.boundZSetOps("zSetKey").add("zSetVaule", 100D);
//2、通过BoundValueOperations设置值
BoundZSetOperations zSetKey = redisTemplate.boundZSetOps("zSetKey");
zSetKey.add("zSetVaule", 100D);
//3、通过ValueOperations设置值
ZSetOperations zSetOps = redisTemplate.opsForZSet();
zSetOps.add("zSetKey", "zSetVaule", 100D);2)、向集合中插入多个元素,并设置分数
DefaultTypedTuple<String> p1 = new DefaultTypedTuple<>("zSetVaule1", 2.1D);
DefaultTypedTuple<String> p2 = new DefaultTypedTuple<>("zSetVaule2", 3.3D);
redisTemplate.boundZSetOps("zSetKey").add(new HashSet<>(Arrays.asList(p1,p2)));3)、按照排名先后(从小到大)打印指定区间内的元素, -1 为打印全部
Set<String> range = redisTemplate.boundZSetOps("zSetKey").range(0, -1);4)、获得指定元素的分数
Double score = redisTemplate.boundZSetOps("zSetKey").score("zSetVaule");5)、返回集合内的成员个数
Long size = redisTemplate.boundZSetOps("zSetKey").size();6)、返回集合内指定分数范围的成员个数(Double 类型)
Long COUNT = redisTemplate.boundZSetOps("zSetKey").count(0D, 2.2D);7)、返回集合内元素在指定分数范围内的排名(从小到大)
Set byScore = redisTemplate.boundZSetOps("zSetKey").rangeByScore(0D, 2.2D);8)、带偏移量和个数,(key,起始分数,最大分数,偏移量,个数)
Set<String> ranking2 = redisTemplate.opsForZSet().rangeByScore("zSetKey", 0D, 2.2D 1, 3);9)、返回集合内元素的排名,以及分数(从小到大)
Set<TypedTuple<String>> tuples = redisTemplate.boundZSetOps("zSetKey").rangeWithScores(0L, 3L);
for (TypedTuple<String> tuple : tuples) {
System.out.println(tuple.getValue() + " : " + tuple.getScore());
}ss10)、返回指定成员的排名
//从小到大
Long startRank = redisTemplate.boundZSetOps("zSetKey").rank("zSetVaule");
//从大到小
Long endRank = redisTemplate.boundZSetOps("zSetKey").reverseRank("zSetVaule");11)、从集合中删除指定元素
redisTemplate.boundZSetOps("zSetKey").remove("zSetVaule");12)、删除指定索引范围的元素(Long 类型)
redisTemplate.boundZSetOps("zSetKey").removeRange(0L,3L);13)、删除指定分数范围内的元素(Double 类型)
redisTemplate.boundZSetOps("zSetKey").removeRangeByScorssse(0D,2.2D);14)、为指定元素加分(Double 类型)
Double score = redisTemplate. boundZSetOps ("zSetKey"). incrementScore ("zSetVaule", 1.1D);