1. 程式人生 > >Spring Data Redis的RedisTemplate的坑

Spring Data Redis的RedisTemplate的坑

自己搭的一個分散式系統,使用的是springboot2.0.3+springcloud Finchley
當時在user服務中存入一個值,然後在api服務中使用相同的key取的時候發現取不出來,然後各種排除:

  • 1 檢查api服務和user服務中的redis連線的機器是否一致(一致)
  • 2 分別寫兩個測試方法,斷點跟進發現存入的時候沒有問題,取得時候發現沒有值,此時利用IntelliJ IDEA工具查詢兩個服務中的所有的key發現一個有,另外一個沒有,推測應該是存入的key發生了變化。

    通過視覺化工具發現存入的key前面都有一串字串,查了一下預設配置的時候是JdkSerializationRedisSerializer

    進行序列化資料,加上去的。它不僅僅會在value或hashvalue上加,也會在key和hashkey上加,所以取不到。

解決方式:設定RedisSerializer

方式一:

RedisConfig:

package com.fch.user.config.redisConfid;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework
.data.redis.core.RedisTemplate; import org.springframework.data.redis.serializer.RedisSerializer; @Configuration public class RedisConfig { private RedisTemplate redisTemplate; @Autowired(required = false) public void setRedisTemplate(RedisTemplate redisTemplate) { RedisSerializer stringSerializer = new StringRedisSerializerUtil();
redisTemplate.setKeySerializer(stringSerializer); redisTemplate.setValueSerializer(stringSerializer); redisTemplate.setHashKeySerializer(stringSerializer); redisTemplate.setHashValueSerializer(stringSerializer); this.redisTemplate = redisTemplate; } }

StringRedisSerializerUtil

package com.fch.user.config.redisConfid;

import com.alibaba.fastjson.JSON;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.util.Assert;

import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;

/**
 * 因為預設使用JdkSerializationRedisSerializer進行資料序列化 (包括key和value)
 */
public class StringRedisSerializerUtil implements RedisSerializer<Object> {

    private final Charset charset;

    private final String target = "\"";

    private final String replacement = "";

    /**
     * {@link StringRedisSerializer} to use 7 bit ASCII, a.k.a. ISO646-US, a.k.a. the Basic Latin block of the Unicode
     * character set.
     *
     * @see StandardCharsets#US_ASCII
     * @since 2.1
     */
    public static final StringRedisSerializer US_ASCII = new StringRedisSerializer(StandardCharsets.US_ASCII);

    /**
     * {@link StringRedisSerializer} to use ISO Latin Alphabet No. 1, a.k.a. ISO-LATIN-1.
     *
     * @see StandardCharsets#ISO_8859_1
     * @since 2.1
     */
    public static final StringRedisSerializer ISO_8859_1 = new StringRedisSerializer(StandardCharsets.ISO_8859_1);

    /**
     * {@link StringRedisSerializer} to use 8 bit UCS Transformation Format.
     *
     * @see StandardCharsets#UTF_8
     * @since 2.1
     */
    public static final StringRedisSerializer UTF_8 = new StringRedisSerializer(StandardCharsets.UTF_8);

    /**
     * Creates a new {@link StringRedisSerializer} using {@link StandardCharsets#UTF_8 UTF-8}.
     */
    public StringRedisSerializerUtil() {
        this(StandardCharsets.UTF_8);
    }

    /**
     * Creates a new {@link StringRedisSerializer} using the given {@link Charset} to encode and decode strings.
     *
     * @param charset must not be {@literal null}.
     */
    public StringRedisSerializerUtil(Charset charset) {

        Assert.notNull(charset, "Charset must not be null!");
        this.charset = charset;
    }

    @Override
    public byte[] serialize(Object o) throws SerializationException {
        String string = JSON.toJSONString(o);
        if (string == null) {
            return null;
        }
        string = string.replace(target, replacement);
        return string.getBytes(charset);
    }

    /*
     * (non-Javadoc)
     * @see org.springframework.data.redis.serializer.RedisSerializer#deserialize(byte[])
     */
    @Override
    public String deserialize( byte[] bytes) {
        return (bytes == null ? null : new String(bytes, charset));
    }
}

這種配置之後就可以正常了

方式二

因為發現方法名都比較怪,直接封裝一下,實際上也是配置了序列化方式

RedisServiceImpl

package com.fch.user.service.impl;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.*;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.stereotype.Service;

import java.io.Serializable;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * Created with IntelliJ IDEA.
 * Date: 2018/7/25
 * Time: 下午2:41
 * Description: No Description
 */

@Slf4j
@Service
@SuppressWarnings({"unchecked","rawtypes"})
public class RedisServiceImpl {

    /*@Autowired*/
    private RedisTemplate redisTemplate;

    /**
     * 寫入快取
    * @Title:set
    * @Description:TODO
    * @param :@param key
    * @param :@param value
    * @param :@return
    * @return :boolean
    * @throws
     */
    public boolean set(final String key,Object value) {
        boolean result = false;
        try {
            ValueOperations<Serializable,Object> operations = redisTemplate.opsForValue();
            operations.set(key, value);
            result = true;
        } catch (Exception e) {
            log.error("==>>寫入快取出錯" + e.getMessage());
        }
        return result;
    }

    /**
     * 寫入快取設定過期時間
    * @Title:set
    * @Description:TODO
    * @param :@param key
    * @param :@param value
    * @param :@param expireTime
    * @param :@return
    * @return :boolean
    * @throws
     */
    public boolean set(final String key, Object value, Long expireTime) {
        log.info("--------------寫入快取設定過期時間---------------");
        boolean result = false;
        try {
            ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
            operations.set(key, value);
            redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
            result = true;
        } catch (Exception e) {
            log.error("==>>寫入快取出錯並設定過期時間" + e.getMessage());
        }
        return result;
    }

    /**
     * 批量刪除對應的value
     * @param keys
     */
    public void remove(final String... keys) {
        for (String key : keys) {
            remove(key);
        }
    }

    /**
     * 批量刪除key
     * @param pattern
     */
    public void removePattern(final String pattern) {
        Set<Serializable> keys = redisTemplate.keys(pattern);
        if (keys.size() > 0)
            redisTemplate.delete(keys);
    }

    /**
     * 刪除對應的value
     * @param key
     */
    public void remove(final String key) {
        if (exists(key)) {
            redisTemplate.delete(key);
        }
    }

    /**
     * 判斷快取中是否有對應的value
     * @param key
     * @return
     */
    public boolean exists(final String key) {
        return redisTemplate.hasKey(key);
    }

    /**
     * 讀取快取
     * @param key
     * @return
     */
    public Object get(final String key) {
        Object result = null;
        ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
        result = operations.get(key);
        return result;
    }

    /**
     * 雜湊 新增
     * @param key
     * @param hashKey
     * @param value
     */
    public void hmSet(String key, Object hashKey, Object value){
        HashOperations<String, Object, Object> hash = redisTemplate.opsForHash();
        hash.put(key,hashKey,value);
    }

    /**
     * 雜湊獲取資料
     * @param key
     * @param hashKey
     * @return
     */
    public Object hmGet(String key, Object hashKey){
        HashOperations<String, Object, Object>  hash = redisTemplate.opsForHash();
        return hash.get(key,hashKey);
    }

    /**
     * 列表新增
     * @param k
     * @param v
     */
    public void lPush(String k,Object v){
        ListOperations<String, Object> list = redisTemplate.opsForList();
        list.rightPush(k,v);
    }

    /**
     * 列表獲取
     * @param k
     * @param l
     * @param l1
     * @return
     */
    public List<Object> lRange(String k, long l, long l1){
        ListOperations<String, Object> list = redisTemplate.opsForList();
        return list.range(k,l,l1);
    }

    /**
     * 集合新增
     * @param key
     * @param value
     */
    public void add(String key,Object value){
        SetOperations<String, Object> set = redisTemplate.opsForSet();
        set.add(key,value);
    }

    /**
     * 集合獲取
     * @param key
     * @return
     */
    public Set<Object> setMembers(String key){
        SetOperations<String, Object> set = redisTemplate.opsForSet();
        return set.members(key);
    }

    /**
     * 有序集合新增
     * @param key
     * @param value
     * @param scoure
     */
    public void zAdd(String key,Object value,double scoure){
        ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();
        zset.add(key,value,scoure);
    }

    /**
     * 有序集合獲取
     * @param key
     * @param scoure
     * @param scoure1
     * @return
     */
    public Set<Object> rangeByScore(String key,double scoure,double scoure1){
        ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();
        return zset.rangeByScore(key, scoure, scoure1);
    }


    @Autowired(required = false)
    public void setRedisTemplate(RedisTemplate redisTemplate) {
        RedisSerializer stringSerializer = new StringRedisSerializer();
        redisTemplate.setKeySerializer(stringSerializer);
        redisTemplate.setValueSerializer(stringSerializer);
        redisTemplate.setHashKeySerializer(stringSerializer);
        redisTemplate.setHashValueSerializer(stringSerializer);
        this.redisTemplate = redisTemplate;
    }
}

2018-09-07

相關推薦

Spring-Data-JPA 爬

lse 失效 get 保存 con insert long 字段長度 CA 一: 實體類的常用註解 2.1 @Entity 標識這個 pojo 是一個 jpa 實體 2.2 @Table(name = "表名") 指定類對應的數據庫表名 2.3 @Id 標記某一字段為表主鍵

【solr】Spring data solr Document is missing mandatory uniqueKey field: id 注意這個

Caused by: org.apache.solr.client.solrj.impl.HttpSolrServer$RemoteSolrException: Document is missing mandatory uniqueKey field: id at org.apache.solr

spring-data-jpa(三) ->今天踩的

最近升級使用了Spring boot 2.0 發現Service層報錯時,事物仍然進行了提交。通過查詢各方資料。大致原因歸納為一下幾種: 1、檢查你方法是不是public的 2、你的異常型別是不是unchecked異常  如果我想check異常也想回滾怎麼辦,註解上面寫明異常型別即

spring data jpa 使用過程中出現的,請繞行

weLive spring data 的使用過程中出現的問題,以及解決方式 資料庫使用的sqlserver 首先我們這裡有manyToOne 和oneToMany,oneToOne三種表與表之間的對映方式 [email protected](fetch = F

Spring Data Redis的RedisTemplate的

自己搭的一個分散式系統,使用的是springboot2.0.3+springcloud Finchley 當時在user服務中存入一個值,然後在api服務中使用相同的key取的時候發現取不出來,然後各種排除: 1 檢查api服務和user服務中的redis

Spring Boot整合Spring Data Elasticsearch 踩

首先來看官網給的版本要求: 紅框這欄指的是:Elasticsearch安裝版本(windows安裝版本或Linux按照版本) 最新因為專案需要elasticsearch,採用今天搞了好久,專案啟動就報如下錯誤: org.elasticsearch.transport

Spring Data JPA的save之

問題因為想要用mysql自增id,想要在save之後獲取這個儲存的實體的id判斷是否插入成功,一直以為Spring Data JPA中的save方法執行結束之後,save(entity)中的entity就會自動被更新為儲存的entity,但是其實不是這樣的,save之後這個實

spring data jpa 裡 Dao層中Repository和JpaSpecificationExecutor的一個小

public interface LabelRepository extends Repository<Label, Lon

spring-data-redis 使用過程中踩過的

spring-data-redis簡介 Spring-data-redis是spring大家族的一部分,提供了在srping應用中通過簡單的配置訪問redis服務,對reids底層開發包(Jedis, JRedis, and RJC)進行了高度封裝,RedisTemplate提供了redis各種操作、異常處

Spring Data JPA 實例查詢

customer 數據庫表 查詢方式 記錄 如何 三、認識“實例查詢” 1、概念定義: 上面例子中,是這樣創建“實例”的:Example<Customer> ex = Example.of(customer, matcher);我們看到,Example對象,由custom

Spring Data Jpa緩存介紹

級別 instance osc vid group 進程 config 詳細配置 oca 一級緩存: 會話session、事務級別的,事務退出,緩存就失效了。以id為標識 實體管理器-數據源 操作數據拷貝而非數據源。 二級緩存: 線程級或集群級,以id為標識放到緩存(針

SpringData系列一Spring Data的環境搭建

vendor ssi over str spa ger repos getbean date  本節作為主要講解Spring Data的環境搭建 JPA Spring Data :致力於減少數據訪問層(DAO)的開發量。開發者唯一要做的就是聲音持久層的接口,其他都交給

SpringBoot中使用Spring Data Jpa 實現簡單的動態查詢的兩種方法

ppr eat value table 得到 blog .net ride integer 首先謝謝大佬的簡書文章:http://www.jianshu.com/p/45ad65690e33# 這篇文章中講的是spring中使用spring data jpa,使用了xml配

關於spring-data-mongodb用戶名密碼登錄報錯問題:Failed to authenticate to database

數據 base 設置 thread read ber ram tro pat 一.問題   1.spring-data-mongodb用戶名密碼登錄報錯問題:Failed to authenticate to database org.springframew

spring boot + spring data jpa

分享 users pac frame 配置文件 .sql lda hash chan Spring Data Repository的核心接口是Repository(好像也沒什麽好驚訝的)。這個接口需要領域類(Domain Class)跟領域類的ID類型作為參數。這個接

Spring Boot入門第二天:一個基於Spring Boot的Web應用,使用了Spring Data JPA和Freemarker。

per pan let mysq 應用 posit ble host thead 今天打算從數據庫中取數據,並展示到視圖中。不多說,先上圖: 第一步:添加依賴。打開pom.xml文件,添加必要的依賴,完整代碼如下: <?xml version="1.0" enco

Spring Data Rest如何暴露ID字段

account edi posit rest pri return ride efault adapter /** * restful默認不返回主鍵id, 需要新增配置文件 */ @Configuration class SpringDataRestConfig {

Spring Data 介紹 (一)

tin 可能 動態 javac 行高 spec 增加 核心概念 一個 簡介   Spring Data是什麽       Spring Data是一個用於簡化數據庫訪問,並支持雲服務的開源框架。其主要目標是使得對數據的訪問變得方便快捷 Spring Data JPA能幹什麽

Spring Data HelloWorld(三)

system out factor 環境搭建 spring string rep ret gda 在 Spring Data 環境搭建(二) 的基礎之上 我們改動 http://www.cnblogs.com/fzng/p/7253068.html 定義個一個接口 繼承

Spring Data 開發環境搭建(二)

是不是 lns utf-8 void ext for 實體類 connect domain 首先咱們先創建一個maven工程 在pom.xml加入以下 依賴 <!--Mysql 驅動包--> <dependency> <