1. 程式人生 > >SpringBoot2.0(13)整合Redis詳解及踩過的坑(Could not get a resource from the pool)

SpringBoot2.0(13)整合Redis詳解及踩過的坑(Could not get a resource from the pool)

SpringBoot2.0整合Redis

首先安裝的過程就不提了。上一個專案的redis是配置在Windows下的,整合很簡單,也沒有做什麼配置。這次為了進行測試,裝在了linux下。在SpringBoot整合的過程中遇到了一些小坑,分享一下。

pom檔案中新增依賴

<!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId
>
<version>2.9.0</version> </dependency> <!--引入Json依賴--> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.47</version> </dependency>

可以看到除了Redis我還加入了JSON的依賴,這是因為我之後讀取出來的資料要轉換成JSON串的格式,資料可讀,方便開發。

application.properties檔案中新增配置

#redis配置
#Linux主機地址
spring.redis.host=192.168.78.131
#埠
spring.redis.port=6379
#超時時間,ms
spring.redis.timeout=3000
#連線池的最大連線數
spring.redis.jedis.pool.max-active=10
#連結的最大等待時間ms
spring.redis.jedis.pool.max-wait=3000
#連線池中的最大的等待數量
spring.redis.jedis.pool.max-idle=10

在SpringBoot2.0的版本中timeout變成了Duration型別的,從其原始碼中我們可以看一下是怎麼定義的:

public void setTimeout(Duration timeout) {
        this.timeout = timeout;
    }

所以正常的寫法應該是:

spring.redis.timeout=3000ms

但是這樣也帶來了一個問題,下面再說這個問題是什麼,這裡先按照初始的定義,不會報錯的

正常的人可能還會在配置檔案中新增redis的密碼的配置,沒有密碼的話就不要新增這個配置,就算預設為空也會導致出現錯誤,不能實現OAuth認證,要是有密碼的話就新增上並寫上自己的密碼。

spring.redis.password=

Redis的自定義初始化

首先寫redisConfig的檔案,讀取application.properties檔案中yml的配置

package com.springboot.SecKill.redis;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;


/**
 * Redis的配置
 * @author WilsonSong
 * @date 2018/8/1/001
 */
//作為元件掃描進來
@Component
//讀取配置檔案
@Configuration
@ConfigurationProperties(prefix = "spring.redis")
public class RedisConfig {
    private String host;  //主機
    private int port;  //埠
    private int timeout;  //超時時間

    @Value("${spring.redis.jedis.pool.max-active}")
    private int maxActive;  //連線池最大執行緒數

    @Value("${spring.redis.jedis.pool.max-wait}")
    private long  maxWait;  //等待時間

    @Value("${spring.redis.jedis.pool.max-idle}")
    private int maxIdle;//最大空閒連線

    public String getHost() {
        return host;
    }

    public void setHost(String host) {
        this.host = host;
    }


    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }

    public int getTimeout() {
        return timeout;
    }

    public void setTimeout(int timeout) {
        this.timeout = timeout;
    }

    public int getMaxActive() {
        return maxActive;
    }

    public void setMaxActive(int maxActive) {
        this.maxActive = maxActive;
    }

    public long getMaxWait() {
        return maxWait;
    }

    public void setMaxWait(long maxWait) {
        this.maxWait = maxWait;
    }

    public int getMaxIdle() {
        return maxIdle;
    }

    public void setMaxIdle(int maxIdle) {
        this.maxIdle = maxIdle;
    }
}

上面用了兩種方式來讀取application.properties中的配置,一種是直接設定@ConfigurationProperties(prefix = “spring.redis”),然後變數名與application.properties中的變數名一樣,這樣就可以讀出來了,然後像max-wait這種變數名沒法定義啊,所以又用了@Value(“${spring.redis.jedis.pool.max-idle}”)這種註解的方式來讀取,當然你可以全部影註解的方式來讀取,注意過程中的每一個變數的基本資料型別定義準確。maxWait和timeout這兩個本來都是Duration型別的,但是這裡分別寫成long和int型別的。一會兒再解釋這個問題。

過程中需要從redis連線池中獲取redis服務,所以這裡初始化jedisPool的配置

package com.springboot.SecKill.redis;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Service;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

/**
 * @author WilsonSong
 * @date 2018/8/1/001
 */
@Service
public class RedisPoolFactory {

    @Autowired
    RedisConfig redisConfig;
    /**
     * redis連線池的一些配置
     * @return
     */
    @Bean
    public JedisPool JedisPoolFactory(){
        JedisPoolConfig poolConfig = new JedisPoolConfig();
        poolConfig.setMaxIdle(redisConfig.getMaxIdle());
        poolConfig.setMaxTotal(redisConfig.getMaxActive());
        poolConfig.setMaxWaitMillis((redisConfig.getMaxWait()));

        JedisPool jedisPool = new JedisPool(poolConfig, redisConfig.getHost(),redisConfig.getPort(),redisConfig.getTimeout());
        return jedisPool;
    }

}

這裡解釋下maxWait和timeout這兩個資料型別的問題。首先

poolConfig.setMaxWaitMillis((redisConfig.getMaxWait()));

用到了maxWait這個變數,看一下setMaxWaitMillis()函式的原始碼

public void setMaxWaitMillis(long maxWaitMillis) {
        this.maxWaitMillis = maxWaitMillis;
    }

maxWaitMillis這個變數是long型別的,所以執勤才那麼定義。

同理

 JedisPool jedisPool = new JedisPool(poolConfig, redisConfig.getHost(),redisConfig.getPort(),redisConfig.getTimeout());

這裡面有用到redisConfig.getTimeout(),看一下JedisPool是怎麼初始化的

public JedisPool(GenericObjectPoolConfig poolConfig, String host, int port, int timeout) {
        this(poolConfig, host, port, timeout, (String)null, 0, (String)null);
    }

可以看到timeout是int型別的,你要一開始定義成Duration型別的,然後可能過程中會涉及到資料型別的強制準換,會不會報錯不知道,有興趣的可以試一下。

最後就是初始化redis的方法如get,set等等

package com.springboot.SecKill.redis;

import com.alibaba.fastjson.JSON;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;



/**
 * @author WilsonSong
 * @date 2018/8/1
 */
@Service
public class RedisService {
    private static final Logger logger = LoggerFactory.getLogger(RedisService.class);

    @Autowired
    JedisPool jedisPool;


    public <T> T get(KeyPrefix prefix, String key, Class<T> clazz){
        Jedis jedis = null;
        try{
          jedis = jedisPool.getResource();
          //生成real  key
          String realKey = prefix.getPrefix() + key;
          String str = jedis.get(realKey);
          T t = String2Bean(str, clazz);
          return t;
        }catch (Exception e){
            logger.error("redis連線池異常"+e.getMessage());
            return null;
        }finally {
            if (jedis != null){
               jedis.close();
            }
        }
    }

    public <T> boolean set(KeyPrefix prefix,String key, T value){
        Jedis jedis = null;
        try{
            jedis = jedisPool.getResource();
            String value_new = Bean2String(value);
            if (value_new == null || value_new.length() <0){
                return false;
            }

            //生成real  key
            String realKey = prefix.getPrefix() + key;
            //過期時間
            int seconds = prefix.expireSeconds();
            if (seconds <= 0){
                jedis.set(realKey, value_new);
            }else {
                jedis.setex(realKey,seconds,value_new);
            }

            return true;
        }catch (Exception e){
            logger.error("redis連線池異常"+e.getMessage());
            return false;
        }finally {
            if (jedis != null){
                jedis.close();
            }
        }
    }

    //key 是否存在
    public <T> Boolean exists(KeyPrefix prefix, String key){
        Jedis jedis = null;
        try{
            jedis = jedisPool.getResource();
            //生成real  key
            String realKey = prefix.getPrefix() + key;
            return jedis.exists(realKey);

        }catch (Exception e){
            logger.error("redis連線池異常"+e.getMessage());
            return null;
        }finally {
            if (jedis != null){
                jedis.close();
            }
        }
    }

    //增加key對應的值
    public <T> Long incr(KeyPrefix prefix, String key){
        Jedis jedis = null;
        try{
            jedis = jedisPool.getResource();
            //生成real  key
            String realKey = prefix.getPrefix() + key;
            return jedis.incr(realKey);
        }catch (Exception e){
            logger.error("redis連線池異常"+e.getMessage());
            return null;
        }finally {
            if (jedis != null){
                jedis.close();
            }
        }
    }

    //減少key對應的物件的值
    public <T> Long decr(KeyPrefix prefix, String key){
        Jedis jedis = null;
        try{
            jedis = jedisPool.getResource();
            //生成real  key
            String realKey = prefix.getPrefix() + key;
            return jedis.decr(realKey);
        }catch (Exception e){
            logger.error("redis連線池異常"+e.getMessage());
            return null;
        }finally {
            if (jedis != null){
                jedis.close();
            }
        }
    }

    //bean物件準換為String
    private <T> String Bean2String(T value) {
        if (value == null){
            return null;
        }
        Class<?> clazz = value.getClass();
        if (clazz == int.class || clazz == Integer.class){
            return  ""+value;
        }else if (clazz == String.class){
            return (String)value;
        }else if (clazz == long.class || clazz == Long.class){
            return  ""+value;
        }else {
            return JSON.toJSONString(value);
        }

    }

    //String轉換為bean
    private <T> T String2Bean(String str, Class<T> clazz) {
        if (str == null || str.length() <0 || clazz == null){
            return null;
        }

        if (clazz == int.class || clazz == Integer.class){
            return  (T)Integer.valueOf(str);
        }else if (clazz == String.class){
            return (T)str;
        }else if (clazz == long.class || clazz == Long.class){
            return (T)Long.valueOf(str);
        }else {
            return JSON.toJavaObject(JSON.parseObject(str),clazz);
        }
    }
}

最後在controller中編寫一個方法實現對service層的呼叫即可,就不贅述了。

踩過的坑

執行程式發現報出異常

Could not get a resource from the pool。

其實也就是在執行

jedis = jedisPool.getResource();這一步時出錯了

  1. 首先第一種可能是你的redis服務沒開啟,檢查下。
  2. 確認開啟了之後就修改你的redis.conf檔案,把bind 127.0.0.1改成bind 0.0.0.0,

​ 也就是把redis的訪問許可權有隻能本機訪問改成所有的都能訪問。

  1. 最後可能的原因有你的Linux的防火牆沒有開放Redis的埠,可以配置開啟,也可以直接關掉防火牆,我這裡直接關掉了Linux的防火牆。

我用的是centos7

永久關閉防火牆的方法

//臨時關閉
systemctl stop firewalld
//禁止開機啟動
systemctl disable firewalld

這樣你再測試下,要是還不能用還有別的原因,可以自己上網去看一下具體怎麼解決。

相關推薦

SpringBoot2.013整合RedisCould not get a resource from the pool

SpringBoot2.0整合Redis 首先安裝的過程就不提了。上一個專案的redis是配置在Windows下的,整合很簡單,也沒有做什麼配置。這次為了進行測試,裝在了linux下。在SpringBoot整合的過程中遇到了一些小坑,分享一下。 po

Redis在windows下的安裝啟動解決一個錯誤:Could not get a resource from the pool

由於專案需要,最近在將專案的每個模組改變成一個單獨的服務來進行部署,但是服務寫完之後,在啟動時報了一個錯誤:Could not get a resource from the pool,如下圖所示: 由以上資訊並查閱資料後明白可能是redis沒有啟動,但是公司

redis提示Could not get a resource from the pooljedis連線池配置

起初在JedisPool中配置了50個活動連線,但是程式還是經常報錯:Could not get a resource from the pool 連線池剛開始是這樣配置的: JedisPoolConfig config = new JedisPoolConfig(

SSM整合redis,並且解決Could not get a resource from the pool

第一步:匯入redis依賴 <!-- jedis (一個redis client端的jar)--> <dependency> <groupId>redis.clients</groupId> <artifactI

java 連接 redis集群時報錯:Could not get a resource from the pool

rom idt log 圖片 pool 本機ip redis style exce 由於弄這個的時候浪費了太多的時間,所以才記錄下這個錯,給大夥參考下 檢查了一下,配置啥的都沒問題的,但在redis集群機器上就可以,錯誤如下: Exception in thread "

redis.clients.jedis.exception.JedisConnectionException:Could not get a resource from the pool

class verbose 沒有 mage resource open conf bubuko uri 啟動項目報該異常。原因是因為該項目是需要啟動redis的,報錯原因是因為沒有安裝redis或者沒有手動啟動redis,把redis設置成自啟動就行了 一、下載window

Cannot get Jedis connection,Could not get a resource from the pool,DENIED Redis is running in protec

一個新專案使用redis做純快取,在本機中無障礙使用,redis放到伺服器就出現上面的錯誤。 折騰了小一天排查各種可能性終於解決問題。最後不使用任何框架直接使用jedis 才發現問題的根本是redis開啟了保護模式。 解決如下:連線redis客戶端,使用命令 127.0.0.1:63

RedisCould not get a resource from the pool 實乃叢集配置問題

先說些題外話~自上次確診為鼻竇炎+過敏性鼻炎到現在已經一個月了,最初那會,從下午到晚上頭疼難忍。大概是積勞成疾,以前流鼻涕、打噴嚏的時候從來沒有注意過,結果病根一下爆發。 關鍵在於鎖定問題,開始治療一兩天之後就不會頭疼了。當然,習慣也很重要,再也不敢用力擤鼻子了。 挺過那一陣就好受很多,之後就是鼻塞稍微煩

springboot【redis】打成war包後部署,訪問報could not get a resource from the pool

 Cannot get Jedis connection; nested exception is redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool

redis遠端連線異常:Cannot get Jedis connection/Could not get a resource from the pool

如果是遠端連線redis,多數情況下是沒有禁用127.0.0.1 redis預設是隻允許本機訪問的,需要在redis.conf配置檔案將127.0.0.1給禁用掉,註釋掉即可。允許外部訪問 redis還有個保護模式,預設為yes 改為no, protected-mod

Redis一個異常的解決辦法,異常描述:Could not get a resource from the pool

異常描述:  redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool at redis.clients.util.Pool.getRes

redis JedisConnectionException: Could not get a resource from the pool 的八種可能的原因

HTTP Status 500 - Cannot get Jedis connection; nested exception is redis.clients.jedis.exceptions.JedisConnectionException: Could not get

redisCould not get a resource from the pool 異常解決

專案中用到了redis,測試時發現偶爾會出現在這個錯誤,然後去網上查了下,原來是用完從池子裡取出jedis連線後沒有回收後沒有回收資源導致的特此記錄一下詳細請看下邊的https://blog.csdn.net/qh_java/article/details/54669973

redis:Unable to validate object ;Could not get a resource from the pool;(error) MISCONF Redis is con

原因: 強制關閉Redis快照導致不能持久化。 解決方式: 登入redis : redis-cli 127.0.0.1:6379>config set stop-writes-on-bgsave-error no ok 解決 ! 參考文章:

redis報錯Could not get a resource from the pool問題的解決

概述 上線了一個新專案,結果報錯: redis.clients.jedis.exceptions.JedisException: Could not get a resource from the pool at redis.client

redis報錯Could not get a resource from the pool

很多人說:這是因為配置檔案有問題,最大連線數,失敗等待時間等。 但是如果是一條資料做個簡單測試的話,就不用太關注這裡了。 我的錯是:linux6379沒開放。 6379加入防火牆: vi /etc/sysconfig/iptables -A INPUT -m sta

通過jedis連線redis單機成功,使用redis客戶端可以連線叢集,但使用JedisCluster連線redis叢集一直報Could not get a resource from th

原因是這個地方以前我沒註釋redis.conf檔案中的bind 127.0.0.1 然後做叢集時使用的命令是: ./redis-trib.rb create –replicas 1 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.

Storm 系列—— Storm 整合 Redis

一、簡介 Storm-Redis 提供了 Storm 與 Redis 的整合支援,你只需要引入對應的依賴即可使用: <dependency> <groupId>org.apache.storm</groupId> <artifactId>stor

SpringBoot系列整合thymeleaf

SpringBoot系列(六)整合thymeleaf詳解版 1. thymeleaf簡介  1. Thymeleaf是適用於Web和獨立環境的現代伺服器端Java模板引擎。  2. Thymeleaf的主要目標是為您的開發工作流程帶來優雅的自然模板 -HTML可以在瀏覽器中正確顯示,也可以作為靜態原型工作,從

Immutable React 中實踐 轉載

轉載自:https://zhuanlan.zhihu.com/p/20295971,今天看到這篇文章後情不自禁的轉載過來了,真的非常值得收藏的一篇文章 Shared mutable state is the root of all evil(共享的可變狀態是萬惡之源) -- Pete Hunt