1. 程式人生 > >SpringBoot整合Redis解決叢集共享快取問題

SpringBoot整合Redis解決叢集共享快取問題

需求分析:

應用程式採用整合的方式部署在3臺伺服器上,每臺伺服器上應用請求同一臺資料庫伺服器,應用程式中獲取當前使用者資訊是從當前伺服器上選取的,當前臺傳送求後需在後臺修改當前使用者的相關屬性,然後查詢當前屬性下的一些資料資訊

產生問題:

採用整合的方式部署,會導致當前修改請求傳送到其中一臺伺服器上,該臺伺服器上的使用者資訊修改了,而其他伺服器的使用者資訊並沒有修改,當下一次的請求傳送到的是另一個伺服器,再查詢資料時,查詢到的資料並不是根據修改後屬性下的資料資訊

解決方法:

通過部署redis,將當前使用者資訊儲存在Redis上,幾臺伺服器共同連線一個Redis,獲取當前使用者資訊時,從Redis中獲取,因Redis是一個高效能的key-value資料庫,避免了修改從傳統的關係型資料庫存取值,可以提高效能
SpringBoot中整合Redis
下面詳細描述一下在SpringBoot中整合Redis的步驟,以及當中踩到的坑

下載Redis

中國官網:http://redis.cn/
官網: https://redis.io/
github網址:https://github.com/antirez/redis
可以通過如下方式,下載相應版本
這裡寫圖片描述

在Windows中安裝Redis和啟動

本人下載版本為Redis-x64-2.8.2402,存放路徑D:\BaiduNetdiskDownload\Redis-x64-2.8.2402
在當前檔案加下,開啟cmd命令,輸入命令:redis-server redis.windows.conf
遇到的問題:
這裡寫圖片描述
解決辦法:redis-server redis.windows.conf –maxmemory 200m
正確啟動後介面:
這裡寫圖片描述

SpringBoot專案中的pom.xml檔案中引入依賴

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

在application.properties加入redis配置

# Redis資料庫索引(預設為0)
spring.redis.database=0
# Redis伺服器地址
#spring.redis.host=10.28.124.201
spring.redis.host=10.0.11.210 # 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

RedisConfig配置類,其中@EnableCaching開啟註解 (特別注意,不然redis配置可能不生效)


import org.springframework.cache.CacheManager;
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.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;

/**
 * 〈Redis配置〉
 * @author 
 * @create 2018/6/4
 * @since 1.0.0
 */
@Configuration
@EnableCaching//開啟快取
public class RedisConfig extends CachingConfigurerSupport{

    @Bean
    public CacheManager cacheManager(RedisTemplate<?,?> redisTemplate) {
        CacheManager cacheManager = new RedisCacheManager(redisTemplate);
        return cacheManager;
    }

    @Bean
    public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, String> redisTemplate = new RedisTemplate<String, String>();
        redisTemplate.setConnectionFactory(factory);
        return redisTemplate;
    }
}

編寫RedisService服務,便於存取資料


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.*;
import org.springframework.stereotype.Component;

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

/**
 * 〈Redis操作類〉
 * @author 
 * @create 2018/6/5
 * @since 1.0.0
 */
@Component
public class RedisService {
    @Autowired
    private RedisTemplate redisTemplate;
    /**
     * 寫入快取
     * @param key
     * @param value
     * @return
     */
    public boolean set(final String key, Object value) {
        boolean result = false;
        try {
            ValueOperations operations = redisTemplate.opsForValue();
            operations.set(key, value);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }
    /**
     * 寫入快取設定時效時間
     * @param key
     * @param value
     * @return
     */
    public boolean set(final String key, Object value, Long expireTime) {
        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) {
            e.printStackTrace();
        }
        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);
    }


}

使用例項


@RestController
@RequestMapping
public class LoginController {

    @Resource
    RedisService redisService;


    @RequestMapping("login")
    @ResponseBody
    public Result login(@RequestBody Map<String, Object> param,
                        HttpServletResponse response, HttpSession session) {     

        String account = param.get("userName").toString();

        redisService.remove("account");//若存在,則刪除
        redisService.set("account",account);//設定
        redisService.get("account");//獲取

        return ResultTool.successData(account);
    }


}

關於redis的整合,本文主要參考的了《SpringBoot整合Redis