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 其中一個即可,前者是後者的父類。它們默認已經全部在容器種了.
    //org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration 中已經自動將 RedisTemplate 添加到了容器中,直接獲取使用即可.
    @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 即可。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章