首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Spring 整合 Redis 實現資料快取完整方案:從配置到多資料型別操作封裝

     編輯:Java 相關知識

目標與依賴

目的:減輕資料庫壓力,非單純加速查詢。核心依賴:

  • spring-data-redis
  • jedis(注意版本與 commons-pool 對應)

配置檔分層設計

1. redis.properties 參數外部化

redis.hostName=127.0.0.1
redis.port=6379
redis.timeout=15000
redis.usePool=true
redis.maxIdle=6
redis.minEvictableIdleTimeMillis=300000
redis.numTestsPerEvictionRun=3
redis.timeBetweenEvictionRunsMillis=60000

2. spring-redis.xml 連線工廠與模板

<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
  <property name="maxIdle" value="${redis.maxIdle}"/>
  <property name="minEvictableIdleTimeMillis" value="${redis.minEvictableIdleTimeMillis}"/>
  <property name="numTestsPerEvictionRun" value="${redis.numTestsPerEvictionRun}"/>
  <property name="timeBetweenEvictionRunsMillis" value="${redis.timeBetweenEvictionRunsMillis}"/>
</bean>

<bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
  <property name="poolConfig" ref="jedisPoolConfig"/>
  <property name="hostName" value="${redis.hostName}"/>
  <property name="port" value="${redis.port}"/>
  <property name="timeout" value="${redis.timeout}"/>
  <property name="usePool" value="${redis.usePool}"/>
</bean>

<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
  <property name="connectionFactory" ref="jedisConnectionFactory"/>
  <property name="keySerializer">
    <bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
  </property>
  <property name="valueSerializer">
    <bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"/>
  </property>
</bean>

3. applicationContext.xml 載入屬性檔

<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
  <property name="locations"><value>classpath*:/META-INF/config/redis.properties</value></property>
</bean>
<import resource="spring-redis.xml"/>

4. web.xml 載入 Spring 容器

<context-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>classpath*:/META-INF/applicationContext.xml</param-value>
</context-param>

RedisCacheUtil 通用封裝類

@Service
public class RedisCacheUtil<T> {
    @Autowired @Qualifier("redisTemplate")
    private RedisTemplate<String, Object> redisTemplate;

    // === String / Entity ===
    public <T> ValueOperations<String, T> setCacheObject(String key, T value) {
        ValueOperations<String, T> ops = redisTemplate.opsForValue();
        ops.set(key, value);
        return ops;
    }
    public <T> T getCacheObject(String key) {
        return redisTemplate.opsForValue().get(key);
    }

    // === List ===
    public <T> ListOperations<String, T> setCacheList(String key, List<T> list) {
        ListOperations<String, T> ops = redisTemplate.opsForList();
        if (list != null) list.forEach(v -> ops.rightPush(key, v));
        return ops;
    }
    public <T> List<T> getCacheList(String key) {
        ListOperations<String, T> ops = redisTemplate.opsForList();
        Long size = ops.size(key);
        List<T> result = new ArrayList<>();
        for (int i = 0; i < size; i++) result.add((T) ops.leftPop(key));
        return result;
    }

    // === Set ===
    public <T> BoundSetOperations<String, T> setCacheSet(String key, Set<T> set) {
        BoundSetOperations<String, T> ops = redisTemplate.boundSetOps(key);
        if (set != null) set.forEach(ops::add);
        return ops;
    }
    public <T> Set<T> getCacheSet(String key) {
        BoundSetOperations<String, T> ops = redisTemplate.boundSetOps(key);
        Long size = ops.size();
        Set<T> result = new HashSet<>();
        for (int i = 0; i < size; i++) result.add(ops.pop());
        return result;
    }

    // === Map (String Key) ===
    public <T> HashOperations<String, String, T> setCacheMap(String key, Map<String, T> map) {
        HashOperations<String, String, T> ops = redisTemplate.opsForHash();
        if (map != null) map.forEach(ops::put);
        return ops;
    }
    public <T> Map<String, T> getCacheMap(String key) {
        return redisTemplate.opsForHash().entries(key);
    }

    // === Map (Integer Key) ===
    public <T> HashOperations<String, Integer, T> setCacheIntegerMap(String key, Map<Integer, T> map) {
        HashOperations<String, Integer, T> ops = redisTemplate.opsForHash();
        if (map != null) map.forEach(ops::put);
        return ops;
    }
    public <T> Map<Integer, T> getCacheIntegerMap(String key) {
        return redisTemplate.opsForHash().entries(key);
    }
}

啟動時快取熱門資料

@Service
public class StartupCacheLoader implements ApplicationListener<ContextRefreshedEvent> {
    @Autowired private RedisCacheUtil<Object> redisCache;
    @Autowired private BrandStoreService brandStoreService;

    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        if (event.getApplicationContext().getDisplayName().contains("Root")) {
            Map<Integer, City> cityMap = new HashMap<>();
            brandStoreService.selectAllCityMessage().forEach(c -> cityMap.put(c.getCityId(), c));
            redisCache.setCacheIntegerMap("cityMap", cityMap);

            Map<Integer, Country> countryMap = new HashMap<>();
            brandStoreService.selectAllCountryMessage().forEach(c -> countryMap.put(c.getCountryId(), c));
            redisCache.setCacheIntegerMap("countryMap", countryMap);
        }
    }
}

業務層使用範例

@Autowired private RedisCacheUtil<User> redisCache;

@RequestMapping("testGetCache")
public void testGetCache() {
    Map<Integer, City> cities = redisCache.getCacheIntegerMap("cityMap");
    Map<Integer, Country> countries = redisCache.getCacheIntegerMap("countryMap");
    cities.forEach((k, v) -> System.out.println("City " + k + ": " + v));
    countries.forEach((k, v) -> System.out.println("Country " + k + ": " + v));
}

生產環境強化建議

  1. 序列化優化:改用 GenericJackson2JsonRedisSerializer 替代 JDK 序列化,跨語言相容、體積更小
  2. 快取策略:引入 @Cacheable、@CacheEvict 註解聲明式快取
  3. 分散式鎖:redisTemplate.opsForValue().setIfAbsent(key, value, timeout) 實現分散式鎖
  4. 管道批次:redisTemplate.executePipelined() 批次操作減少 RTT
  5. 監控告警:整合 Redis Exporter + Prometheus 監控記憶體、命中率、慢查詢
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved