目的:減輕資料庫壓力,非單純加速查詢。核心依賴:
spring-data-redisjedis(注意版本與 commons-pool 對應)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
<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>
<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"/>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:/META-INF/applicationContext.xml</param-value>
</context-param>
@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));
}
GenericJackson2JsonRedisSerializer 替代 JDK 序列化,跨語言相容、體積更小@Cacheable、@CacheEvict 註解聲明式快取redisTemplate.opsForValue().setIfAbsent(key, value, timeout) 實現分散式鎖redisTemplate.executePipelined() 批次操作減少 RTT