目录
RedisTemplate 常用方法
org.springframework.data.redis.core.RedisTemplate 常用方法(本文环境 Spring Boot 2.1.3):
方法 | 描述 |
---|---|
Boolean expire(K key, final long timeout, final TimeUnit unit) | 为指定的 key 指定缓存失效时间。时间一到 key 会被移除。key 不存在时,不影响。 |
Boolean expireAt(K key, final Date date) | 设置 key 失效日期 |
Long getExpire(K key) | 获取 key 的剩余过期时间。 -1 表示永久有效。-2 表示 key 不存在。 |
Long getExpire(K key, final TimeUnit timeUnit) | 获取 key 的剩余过期时间,并换算成指定的时间单位 |
Boolean hasKey(K key) | 判断 key 是否存在 |
Boolean delete(K key) | 删除指定的 key |
Long delete(Collection keys) | 删除多个 key |
RedisSerializer<?> getDefaultSerializer() | 获取默认的序列化方式。RedisTemplate 是 JdkSerializationRedisSerializer;StringRedisTemplate 是 StringRedisSerializer |
Set keys(K pattern) | 获取整个库下符合指定正则的所有 key,如 keys(*) 获取所有 key |
Boolean move(K key, final int dbIndex) | 将 key 从当前库移动目标库 dbIndex |
ClusterOperations<K, V> opsForCluster() | 获取 ClusterOperations 用于操作集群 |
GeoOperations<K, V> opsForGeo() | 获取 GeoOperations 用于操作地图 |
<HK, HV> HashOperations<K, HK, HV> opsForHash() | 获取 HashOperations 用于操作 hsha 数据类型 |
ListOperations<K, V> opsForList() | 获取 ListOperations 用于操作 list 类型 |
SetOperations<K, V> opsForSet() | 获取 SetOperations 用于操作无序集合 |
ValueOperations<K, V> opsForValue() | 获取 ValueOperations 用于操作 String类型 |
ZSetOperations<K, V> opsForZSet() | 获取 ValueOperations 用于操作有序集合 |
rename(K oldKey, K newKey) | 为 oldKey 进行重命名 |
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.core.types.RedisClientInfo;
import org.springframework.test.context.junit4.SpringRunner;
import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
@RunWith(SpringRunner.class)
@SpringBootTest
public class RedisStuWebApplicationTests {
//注入 RedisTemplate 或者 StringRedisTemplate 其中一个即可,前者是后者的父类。它们默认已经全部在容器种了.
@Resource
private RedisTemplate redisTemplate;
@Resource
private StringRedisTemplate stringRedisTemplate;
@Test
public void test1() throws InterruptedException {
ValueOperations<String, String> opsForValue = stringRedisTemplate.opsForValue();
opsForValue.set("wmx_name", "Zhang San");//设置字符串值
System.out.println(opsForValue.get("wmx_name"));//Zhang San
stringRedisTemplate.expire("wmx_name", 60, TimeUnit.SECONDS);//设置 key 失效时间
// for (int i = 0; i < 15; i++) {
// System.out.println(stringRedisTemplate.getExpire("wmx_name"));
// System.out.println(stringRedisTemplate.getExpire("wmx_name", TimeUnit.SECONDS));
// Thread.sleep(1000);
// }
//判断是否含有指定的 key
System.out.println(stringRedisTemplate.hasKey("wmx_name") + ", " + stringRedisTemplate.hasKey("wmx_name_2"));//true, false
opsForValue.set("age", "33");
opsForValue.set("address", "长沙");
stringRedisTemplate.delete("age");//删除 key
Date stopDate = new Date();
stopDate.setTime(System.currentTimeMillis() + (60 * 1000));
stringRedisTemplate.expireAt("address", stopDate);//设置 key 1 分钟后失效
List<RedisClientInfo> clientList = stringRedisTemplate.getClientList();
System.out.println(clientList);
System.out.println(redisTemplate.getDefaultSerializer());//获取默认序列化方式
Set<String> keys = stringRedisTemplate.keys("*");//获取当前库下所有的 key
System.out.println("keys=" + keys);
Boolean move = stringRedisTemplate.move("address", 2);//将 address 移动 2 号数据库
System.out.println("move=" + move);
opsForValue.set("info", "描述");
System.out.println(opsForValue.get("info"));
stringRedisTemplate.rename("info", "summary");//对 key 进行重命名
}
}
RedisTemplate 序列化方式
1、StringRedisTemplate 继承 RedisTemplate,主要区别就是前者默认使用 StringRedisSerializer 序列化 String,后者默认使用 JdkSerializationRedisSerializer 序列化对象。
2、RedisTemplate<K, V> 可以用来存储对象,如 Map、List 、Set、POJO 等,但对象需要实现 Serializable 序列化接口。此种方式序列化时,以二进制数组方式存储,内容没有可读性。
Map<String, Object> dataMap = new HashMap<>();
dataMap.put("id", 1001);
dataMap.put("name", "张三");
HashOperations opsForHash = redisTemplate.opsForHash();
opsForHash.putAll("map_1",dataMap);
redisTemplate.expire("map_1",60,TimeUnit.SECONDS);
Map map_11 = opsForHash.entries("map_1");
System.out.println(map_11);//{name=张三, id=1001}
3、StringRedisTemplate 专门用来存储字符串,StringRedisTemplate extends RedisTemplate<String, String>。序列化接口 org.springframework.data.redis.serializer.RedisSerializer 的实现类如下:
序列化方式 | 描述 |
---|---|
FastJsonRedisSerializer | 采用 com.alibaba.fastjson 进行序列化与反序列化 ,提供了 (Class type) 参数的构造器,需要传入对象类型。 |
GenericFastJsonRedisSerializer | 提供了基本的 GenericFastJsonRedisSerializer() 构造器。 |
GenericJackson2JsonRedisSerializer | 与 Jackson2JsonRedisSerializer 功能差不多,构造函数可以指定 Class,默认为 String. |
GenericToStringSerializer | 需要调用者传一个对象到字符串互转的 Converter(相当于转换为字符串的操作交给转换器去做) |
Jackson2JsonRedisSerializer | 采用 com.fasterxml.jackson 进行序列化与反序列化。优点是速度快,序列化后的字符串短小精悍,不需要实现Serializable接口。构造函数必须传入 Class 类型。 |
JdkSerializationRedisSerializer | RedisTemplate 默认的序列化方式。要求存储的对象必须实现java.io.Serializable接口。序列化后的结果非常庞大。存储的为二进制数据,对开发者不友好。 |
OxmSerializer | 以 xml 格式存储,解析起来比较复杂,效率也比较低 |
StringRedisSerializer | StringRedisTemplate 默认的字符串序列化方式。key 和 value 都会采用此方式进行序列化,是被推荐使用的,对开发者友好,轻量级,效率也比较高。此时只能是 String,不能是其它对象,否则报错。 |
4、本文环境 Spring Boot 2.1.3 + Java JDK 1.8,下面以指定 Jackson2JsonRedisSerializer 序列化方式为例:
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
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 {
//自定义 RedisTemplate 序列化方式
@Bean
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();//创建 RedisTemplate,key 和 value 都采用了 Object 类型
redisTemplate.setConnectionFactory(redisConnectionFactory);//绑定 RedisConnectionFactory
//创建 Jackson2JsonRedisSerializer 序列方式,对象类型使用 Object 类型,
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);//设置一下 jackJson 的 ObjectMapper 对象参数
// 设置 RedisTemplate 序列化规则。因为 key 通常是普通的字符串,所以使用 StringRedisSerializer 即可。
// 而 value 是对象时,才需要使用序列化与反序列化
redisTemplate.setKeySerializer(new StringRedisSerializer());// key 序列化规则
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);// value 序列化规则
redisTemplate.setHashKeySerializer(new StringRedisSerializer());// hash key 序列化规则
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);// hash value 序列化规则
redisTemplate.afterPropertiesSet();//属性设置后操作
return redisTemplate;//返回设置好的 RedisTemplate
}
}
5、RedisTemplate 使用就很简单了,保存数据与读取数据时,直接操作对象即可,会自动进行序列化与反序列化:
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
@RestController
public class RedisController {
@Resource
private RedisTemplate redisTemplate;
//设置缓存:localhost:8080/redis/save
@GetMapping("redis/save")
public String test1() {
ValueOperations opsForValue = redisTemplate.opsForValue();
ListOperations opsForList = redisTemplate.opsForList();
HashOperations opsForHash = redisTemplate.opsForHash();
User user1 = new User(100, "张三", new Date());
User user2 = new User(200, "李四", new Date());
User user3 = new User(300, "王五", new Date());
User user4 = new User(400, "马六", new Date());
//设置缓存
opsForValue.set(RedisController.class.getName() + "_string_user1", user1);
opsForList.rightPushAll(RedisController.class.getName() + "_list_user2", user2, user3);
opsForHash.put(RedisController.class.getName() + "_map", "user4", user4);
//设置 key 失效时间
redisTemplate.expire(RedisController.class.getName() + "_string_user1",60, TimeUnit.SECONDS);
redisTemplate.expire(RedisController.class.getName() + "_list_user2",60, TimeUnit.SECONDS);
redisTemplate.expire(RedisController.class.getName() + "_map",60, TimeUnit.SECONDS);
return "缓存成功.";
}
//查询缓存:localhost:8080/redis/get
@GetMapping("redis/get")
public String test2() {
ValueOperations opsForValue = redisTemplate.opsForValue();
ListOperations opsForList = redisTemplate.opsForList();
HashOperations opsForHash = redisTemplate.opsForHash();
//读取缓存,如果 key 不存在,则返回为 null.
User user1 = (User)opsForValue.get(RedisController.class.getName() + "_string_user1");
List<User> list = opsForList.range(RedisController.class.getName() + "_list_user2", 0, -1);
User user4 = (User)opsForHash.get(RedisController.class.getName() + "_map", "user4");
System.out.println(user1);//User{id=100, name='张三', birthday=Wed Nov 27 15:35:20 CST 2019}
//[User{id=200, name='李四', birthday=Wed Nov 27 15:35:20 CST 2019}, User{id=300, name='王五', birthday=Wed Nov 27 15:35:20 CST 2019}]
System.out.println(list);
System.out.println(user4);//User{id=400, name='马六', birthday=Wed Nov 27 15:35:20 CST 2019}
return "查询成功.";
}
}
class User {
private Integer id;
private String name;
private Date birthday;
public User() {
}
public User(Integer id, String name, Date birthday) {
this.id = id;
this.name = name;
this.birthday = birthday;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", birthday=" + birthday +
'}';
}
}
关于 RedisTemplate 的序列化,实际生产中遇到一次需要将数据库查出来的一个 List 对象放到 Redis 中缓存,当时数据量达到 20 万行,结果 put 到缓存的时间长达 6、7 秒,然后当使用 alibaba 的 fastjson 手动先将 List 对象序列化为字符串,然后作为普通的字符串使用 ValueOperations set 到缓存,此时 set 的时间降到了 100 毫秒内,而 fastjson 序列化对象同样非常之快。取值时,同样将取出的字符串使用 fastjosn 手动反序列化成 List 即可。