Spring Boot 2.1.3 RedisTemplate 常用方法 与 序列化方式

目录

RedisTemplate 常用方法

RedisTemplate 序列化方式


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 即可。

发布了458 篇原创文章 · 获赞 884 · 访问量 92万+

猜你喜欢

转载自blog.csdn.net/wangmx1993328/article/details/103282121