Springboots + Redis

一、Redis簡介

        Redis是NoSql(非關係型數據庫)中的一種,是C語言開發的一個高性能鍵值數據庫,即通過一些鍵值類型來存儲數據。Redis的鍵值類型有:String字符類型、map散列類型、list列表類型、set集合類型、sortedset有序集合類型。

        Redis適用場景:秒殺庫存覈減,常用訪問數據量高的相對固定數據,分佈式集羣架構中的session分離,聊天室的好友列表,任務隊列等。

        Redis 優勢:(1)性能極高 , Redis能讀的速度是110000次/s,寫的速度是81000次/s;(2)豐富的數據類型; (3)Redis的所有操作都是原子性的,同時Redis還支持對幾個操作全並後的原子性執行;(4) Redis還支持 publish/subscribe, 通知, key 過期等等特性。

        Redis的詳細介紹、配置及命令可以參考官方文檔:https://www.redis.net.cn/tutorial/3504.html

        Linux下的Redis安裝可以參考:Linux服務器搭建——Redis的安裝

        Windows下的Redis安裝:

        (1)下載Windows版本Redis:https://github.com/MSOpenTech/redis/releases,下載最新的windows X64版本的壓縮包(選擇.zip)

        (2)下載之後解壓redis,在redis目錄打開cmd,啓動redis:redis-server.exe redis.windows.conf

(PS:此處指定了配置文件:redis.windows.conf。打開該文件可修改配置。常見的配置修改是將bind 127.0.0.1和requirepass foobared,這兩行註釋掉,即在前面加上#)

二、SpringBoots整合Redis

        在SpringBoot中一般使用RedisTemplate提供的方法來操作Redis。

 

(1)首先搭建一個Springboot項目,注意依賴中引入包的版本,我直接用的spring initial搭的項目。

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.2.2.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>

(2)引入redis的依賴:

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

         Redis自1.4.7之後,依賴包已經改成spring-boot-starter-data-redis了。這個依賴中集成了一些redis需要的配置(比如工廠模型JedisConnectionFactory、JredisConnectionFactory、LettuceConnectionFactory、SrpConnectionFactory),不需要自己再配置RedisConfig類(但是如果不滿足自己需要,也可以重寫,可以參考以下兩篇博文:

spring data redis快速上手

SpringBoot整合Redis及Redis工具類撰寫)。引入包版本不正確會導致類找不到等系列問題。

(3)在application.properties中添加redis的相關配置

# 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=200
spring.redis.jedis.pool.max-active=200
# 連接池最大阻塞等待時間(使用負值表示沒有限制)
#spring.redis.pool.max-wait=-1
spring.redis.jedis.pool.max-wait=-1ms
# 連接池中的最大空閒連接
#spring.redis.pool.max-idle=10
spring.redis.jedis.pool.max-idle=10
# 連接池中的最小空閒連接
#spring.redis.pool.min-idle=0
spring.redis.jedis.pool.min-idle=0
# 連接超時時間(毫秒)
spring.redis.timeout=1000ms

(4)測試

         操作完以上三步就可以直接注入RedisTemplate來操作redis了,這裏我是將RedisTemplate的一些方法全都封裝進了RedisUtil,直接使用注入的redisUtil進行的測試。另外我也重新寫了RedisConfig。

        RedisConfig:

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
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;

/**
 * redis配置
 * @author zhangy
 * @date 2020-03-25 18:29
 * @version 1.0
 **/
@Configuration
@EnableCaching //開啓註解
public class RedisConfig extends CachingConfigurerSupport {

    @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;
    }
}

         RedisUtil:(只貼了格式爲String的部分方法,還有hash、set等的數據類型可以自己繼續完善)

@Component
public class RedisUtil {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    /**
     * 指定緩存失效時間
     * @param key
     * @param time
     * @return
     */
    public boolean expire(String key, long time){
        try {
            if(time > 0){
                redisTemplate.expire(key, time, TimeUnit.SECONDS);
            }
            return true;
        }catch (Exception e){
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 根據key獲取過期時間
     * @param key
     * @return
     */
    public long getExipire(String key){
        return redisTemplate.getExpire(key, TimeUnit.SECONDS);
    }

    /**
     * 判斷key是否存在
     * @param key
     * @return
     */
    public boolean hasKey(String key){
        try{
            return  redisTemplate.hasKey(key);
        }catch (Exception e){
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 刪除緩存
     * @param key 可以傳一個或多個
     */
    public void del(String ...key){
        if (key != null && key.length > 0){
            if(key.length == 1){
                redisTemplate.delete(key[0]);
            }else{
                redisTemplate.delete(CollectionUtils.arrayToList(key));
            }
        }
    }

    /**
     * 普通緩存獲取
     * @param key
     * @return
     */
    public Object get(String key){
        return key == null?null:redisTemplate.opsForValue().get(key);
    }

    /**
     * 普通緩存放入
     * @param key
     * @param value
     * @return
     */
    public boolean set(String key, Object value){
        try{
            redisTemplate.opsForValue().set(key, value);
            return true;
        }catch (Exception e){
            e.printStackTrace();
            return false;
        }
    }
}

        測試用例直接貼代碼: 

        參考了很多文章,也是以上面幾個步驟爲主,但是我操作完執行項目的時候遇到了很多問題(當時沒有截圖記錄,不能提供具體的異常信息,還請將就!):

1、啓動時報錯:

        Caused by: org.springframework.beans.factory.support.BeanDefinitionOverrideException: Invalid bean definition with name 'stringRedisTemplate' defined in class path resource 

        這是由於我自己實現了RedisConfig,但是注入的bean的名稱不正確,此處的方法名爲redisTemplate纔可以覆蓋spring-boot-starter-data-redis中自動配置的redisTemplate(詳細解釋可以參考:SpringBoot整合Redis及Redis工具類撰寫)。(此處RedisConfig繼承了CachingConfigurerSupport,沒有太多必要,可以不用繼承)

2、啓動時報錯:

         'org.springframework.data.redis.connection.RedisConnectionFactory' that could not be found.

         這個問題困擾了我兩天,一直沒有解決,後來發現還是redis包依賴的問題。(其實一開始也發現,但是依賴一直沒有引對,也有可能是別的一些依賴有影響)所以pom中引入依賴的時候一定要注意版本號(可參考:springboot+redis項目實戰)。(如果想查看工程用的包所依賴的包的版本可以去http://mvnrepository.com/輸入對應的包如spring-data-redis)

3、連接不上redis:

        ERR Client sent AUTH, but no password is set

        這個就是上面提到的redis的配置問題了,註釋掉相應的配置就可以了。

(有些問題可能也是我誤打誤撞解決了,有不足的地方還請指出)

 

項目工程:https://github.com/CoolITDog/test-redis.git

 

 

 

 

 

 

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