天天看點

從零開始教你舒服的使用RedisTemplate操作Redis資料

作者:Java牛逼架構師

SpringBoot快速操作Redis資料

在SpringBoot架構中提供了spring-boot-starter-data-redis的依賴元件進行操作Redis服務,當引入了該元件之後,隻需要配置Redis的配置即可進行連結Redis服務并且進行操作Redis服務資料。

針對于不同的版本有了不同的底層用戶端的支援的底層用戶端架構是不同的:目前常見的用戶端為Jedis和Lettuce。

低版本SpringBoot支援的Jedis

Jedis是很常用的Redis的Java 實作的用戶端。支援基本的資料類型如:String、Hash、List、Set、Sorted Set。

特點:使用阻塞的 I/O,方法調用同步,程式流需要等到 socket 處理完 I/O 才能執行,不支援異步操作。Jedis 用戶端執行個體不是線程安全的,需要通過連接配接池來使用 Jedis。

高版本版本SpringBoot支援的Lettuce

Lettuce用戶端主要用于線程安全同步,異步和響應使用,支援叢集,Sentinel,管道和編碼器。

基于 Netty 架構的事件驅動的通信層,其方法調用是異步的。Lettuce 的 API 是線程安全的,是以可以操作單個 Lettuce 連接配接來完成各種操作。

spring-data-redis針對jedis提供了如下功能:

Spring Boot 的 spring-boot-starter-data-redis 為 Redis 的相關操作提供了一個高度封裝的 RedisTemplate 類,而且對每種類型的資料結構都進行了歸類,實作連接配接池自動管理,提供了一個高度封裝的“RedisTemplate”類。 針對jedis/Lettuce用戶端中大量api進行了歸類封裝,将同一類型操作封裝為operation接口。

通用的接口類型工廠方法

提供了對key的“bound”(綁定)便捷化操作API,可以通過bound封裝指定的key,然後進行一系列的操作而無須“顯式”的再次指定Key,即BoundKeyOperations:

從零開始教你舒服的使用RedisTemplate操作Redis資料
  • ValueOperations - BoundValueOperations:String類型的簡單K-V操作
  • SetOperations - BoundSetOperations:set類型資料操作
  • ZSetOperations - BoundListOperations:zset類型資料操作
  • HashOperations - BoundSetOperations:針對map類型的資料操作
  • ListOperations - BoundHashOperations:針對list類型的資料操作

序列化/反序列化的擴充機制

針對資料的“序列化/反序列化”,提供了多種可選擇政策(RedisSerializer)

從零開始教你舒服的使用RedisTemplate操作Redis資料

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工具支援】

Jackson2JsonRedisSerializer

使用Jackson庫将對象序列化為JSON字元串。優點是速度快,序列化後的字元串短小精悍,不需要實作Serializable接口。但缺點也非常緻命,那就是此類的構造函數中有一個類型參數,必須提供要序列化對象的類型資訊(.class對象)。 通過檢視源代碼,發現其隻在反序列化過程中用到了類型資訊。

OxmSerializer

提供了将javabean與xml之間的轉換能力,目前可用的三方支援包括jaxb,apache-xmlbeans;redis存儲的資料将是xml工具。不過使用此政策,程式設計将會有些難度,而且效率最低;不建議使用。【需要spring-oxm子產品的支援】

擴充第三方序列化工具

當然了除了以上這幾種基本的序列化器之外您還可以進行自定義一些更加優秀、速度更塊的序列化方式,例如:FastJsonRedisSerializer和KryoRedisSerializer、FSTRedisSerializer等。

RedisSerializer接口

RedisSerializer 基礎接口定義了将對象轉換為位元組數組(二進制資料)的序列化和反序列化方法。建議将實作設計為在序列化和反序列化端處理空對象/空位元組數組。注意,Redis 不接受空鍵或空值,但可以傳回 null(對于不存在的鍵)。

RedisSerializer 接口方法定義

從零開始教你舒服的使用RedisTemplate操作Redis資料

序列化

序列化方法定義如下:

java

byte[] serialize(T t)
           

該方法将給定對象 t 序列化為二進制資料,及位元組數組。注意:對象 t 和傳回值可以為 null。

反序列化

反序列化方法定義如下:

java

T deserialize(byte[] bytes)
           

該方法将從給定的二進制資料(位元組數組)反序列化為一個對象。注意:bytes 位元組數組和傳回值 T 均可以為 null。

注意:如果上面的 serialize() 和 deserialize() 方法在執行時報錯,将抛出org.springframework.data.redis.serializer.SerializationException 異常。

引入spring-boot-starter-data-redis元件

springboot 與redis的整合,pom檔案,依賴如下:

xml

<dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
           

配置對應的application.properties檔案

針對于配置我們按照jedis的配置為基礎案例,如下所示。

properties

# Redis資料庫索引(預設為0)
spring.redis.database=0  
# Redis伺服器位址
spring.redis.host=127.0.0.1
# Redis伺服器連接配接端口
spring.redis.port=6379  
# Redis伺服器連接配接密碼(預設為空)
spring.redis.password=
# 連接配接池最大連接配接數(使用負值表示沒有限制)
spring.redis.pool.max-active=8  
# 連接配接池最大阻塞等待時間(使用負值表示沒有限制)
spring.redis.pool.max-wait=-1  
# 連接配接池中的最大空閑連接配接
spring.redis.pool.max-idle=8  
# 連接配接池中的最小空閑連接配接
spring.redis.pool.min-idle=0  
# 連接配接逾時時間(毫秒)
spring.redis.timeout=0 
           

對應的SpringBoot-Redis的核心配置類

此處需要定義RedisTemplate對象的配置類,其中需要配置對應的RedisConnectionFactory對象類以及對應類型的序列化和反序列化元件起。如下所示

定義對應的redisTemplate對象類

預設是JDK的序列化政策,這裡配置redisTemplate采用的是Jackson2JsonRedisSerializer的序列化政策,參數為redisConnectionFactory。

java

@Bean
    public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){
        //使用Jackson2JsonRedisSerializer來序列化和反序列化redis的value值(預設使用JDK的序列化方式)
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
        ObjectMapper om = new ObjectMapper();
        // 指定要序列化的域,field,get和set,以及修飾符範圍,ANY是都有包括private和public
        om.setVisibility(PropertyAccessor.ALL,JsonAutoDetect.Visibility.ANY);
        // 指定序列化輸入的類型,類必須是非final修飾的,final修飾的類,比如String,Integer等會抛出異常
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        // 配置連接配接工廠
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        //使用StringRedisSerializer來序列化和反序列化redis的key值
        //redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setKeySerializer(jackson2JsonRedisSerializer);
        // 值采用json序列化
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.setHashKeySerializer(jackson2JsonRedisSerializer);
        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }
           

定義對應的StringRedisTemplate對象類

但是對于 string 類型的資料,Spring Boot 還專門提供了 StringRedisTemplate 類,而且官方也建議使用該類來操作 String 類型的資料。stringRedisTemplate預設采用的是String的序列化政策。

java

@Bean
    public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory){
        StringRedisTemplate stringRedisTemplate = new StringRedisTemplate();
        stringRedisTemplate.setConnectionFactory(redisConnectionFactory);
        return stringRedisTemplate;
    }
           

StringRedisTemplate和 RedisTemplate 又有啥差別呢?

  • RedisTemplate 是一個泛型類,而 StringRedisTemplate 不是,後者隻能對鍵和值都為 String 類型的資料進行操作,而前者則可以操作任何類型。
  • 兩者的資料是不共通的,StringRedisTemplate 隻能管理 StringRedisTemplate 裡面的資料,RedisTemplate 隻能管理 RedisTemplate 中 的資料。

定義組合序列化方式

key采用String序列化,value使用jackson序列化,如下代碼所示。

java

@Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
        template.setConnectionFactory(factory);
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        // key采用String的序列化方式
        template.setKeySerializer(stringRedisSerializer);
        // hash的key也采用String的序列化方式
        template.setHashKeySerializer(stringRedisSerializer);
        // value序列化方式采用jackson
        template.setValueSerializer(jackson2JsonRedisSerializer);
        // hash的value序列化方式采用jackson
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        template.afterPropertiesSet();
        return template;
    }
           

定義RedisTemplate的腳手架

将形成一個快速操作資料的工具類,将各種類型的操作類進行封裝處理控制。

  • HashOperations:對hash類型的資料操作
  • ValueOperations:對redis字元串類型資料操作
  • ListOperations:對連結清單類型的資料操作
  • SetOperations:對無序集合類型的資料操作
  • ZSetOperations:對有序集合類型的資料操作

将以上各種類型的類直接進行暴漏,減少調用鍊路的路徑長度。

java

/**
     * 對hash類型的資料操作
     * @param redisTemplate
     * @return
     */
    @Bean
    public HashOperations<String, String, Object> hashOperations(RedisTemplate<String, Object> redisTemplate) {
        return redisTemplate.opsForHash();
    }

    /**
     * 對redis字元串類型資料操作
     * @param redisTemplate
     * @return
     */
    @Bean
    public ValueOperations<String, Object> valueOperations(RedisTemplate<String, Object> redisTemplate) {
        return redisTemplate.opsForValue();
    }

    /**
     * 對連結清單類型的資料操作
     * @param redisTemplate
     * @return
     */
    @Bean
    public ListOperations<String, Object> listOperations(RedisTemplate<String, Object> redisTemplate) {
        return redisTemplate.opsForList();
    }

    /**
     * 對無序集合類型的資料操作
     * @param redisTemplate
     * @return
     */
    @Bean
    public SetOperations<String, Object> setOperations(RedisTemplate<String, Object> redisTemplate) {
        return redisTemplate.opsForSet();
    }

    /**
     * 對有序集合類型的資料操作
     * @param redisTemplate
     * @return
     */
    @Bean
    public ZSetOperations<String, Object> zSetOperations(RedisTemplate<String, Object> redisTemplate) {
        return redisTemplate.opsForZSet();
    }
           

定義基礎層的操作處理定義RedisSupport

除了以上這幾種類型的操作之外,還有一些基礎相關的核心操作類,包含重命名,轉移以及情況整個庫的操作、設定TTL生命周期等。

java

@Component
public class RedisSupport {

	@Autowired
    private RedisTemplate<String, String> redisTemplate;

    /**
     * 預設過期時長,機關:秒
     */
    public static final long DEFAULT_EXPIRE = 60 * 60 * 24;

    /**
     * 不設定過期時長
     */
    public static final long NOT_EXPIRE = -1;

    public boolean existsKey(String key) {
        return redisTemplate.hasKey(key);
    }

    /**
     * 重名名key,如果newKey已經存在,則newKey的原值被覆寫
     *
     * @param oldKey
     * @param newKey
     */
    public void renameKey(String oldKey, String newKey) {
        redisTemplate.rename(oldKey, newKey);
    }

    /**
     * newKey不存在時才重命名
     *
     * @param oldKey
     * @param newKey
     * @return 修改成功傳回true
     */
    public boolean renameKeyNotExist(String oldKey, String newKey) {
        return redisTemplate.renameIfAbsent(oldKey, newKey);
    }

    /**
     * 删除key
     *
     * @param key
     */
    public void deleteKey(String key) {
        redisTemplate.delete(key);
    }

    /**
     * 删除多個key
     *
     * @param keys
     */
    public void deleteKey(String... keys) {
        Set<String> kSet = Stream.of(keys).map(k -> k).collect(Collectors.toSet());
        redisTemplate.delete(kSet);
    }

    /**
     * 删除Key的集合
     *
     * @param keys
     */
    public void deleteKey(Collection<String> keys) {
        Set<String> kSet = keys.stream().map(k -> k).collect(Collectors.toSet());
        redisTemplate.delete(kSet);
    }

    /**
     * 設定key的生命周期
     *
     * @param key
     * @param time
     * @param timeUnit
     */
    public void expireKey(String key, long time, TimeUnit timeUnit) {
        redisTemplate.expire(key, time, timeUnit);
    }

    /**
     * 指定key在指定的日期過期
     *
     * @param key
     * @param date
     */
    public void expireKeyAt(String key, Date date) {
        redisTemplate.expireAt(key, date);
    }

    /**
     * 查詢key的生命周期
     *
     * @param key
     * @param timeUnit
     * @return
     */
    public long getKeyExpire(String key, TimeUnit timeUnit) {
        return redisTemplate.getExpire(key, timeUnit);
    }

    /**
     * 将key設定為永久有效
     *
     * @param key
     */
    public void persistKey(String key) {
        redisTemplate.persist(key);
    }
}
           
至此整體對應的RedisTemplate對象的封裝和擴充就到這裡,可以把代碼介入到你的項目裡面,非常友善的進行操作Redis了,是不是很OK呢?
原文連結:https://www.cnblogs.com/liboware/p/17035032.html

繼續閱讀