一、📦 基础配置与工具类
1. Maven依赖 (pom.xml)
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
</dependencies>
2. 应用配置 (application.yml)
spring:
redis:
host: localhost
port: 6379
password:
database: 0
lettuce:
pool:
max-active: 8
max-idle: 8
min-idle: 0
max-wait: 200ms
shutdown-timeout: 100ms
timeout: 2000ms
3. Redis配置类 (RedisConfig.java)
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.StringRedisSerializer;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(connectionFactory);
StringRedisSerializer stringSerializer = new StringRedisSerializer();
template.setKeySerializer(stringSerializer);
template.setHashKeySerializer(stringSerializer);
GenericJackson2JsonRedisSerializer jsonSerializer = new GenericJackson2JsonRedisSerializer();
template.setValueSerializer(jsonSerializer);
template.setHashValueSerializer(jsonSerializer);
template.afterPropertiesSet();
return template;
}
}
4. Redis通用工具类 (RedisUtil.java)
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
@Component
public class RedisUtil {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
public Boolean delete(String key) {
return redisTemplate.delete(key);
}
public Boolean hasKey(String key) {
return redisTemplate.hasKey(key);
}
public Boolean expire(String key, long timeout, TimeUnit unit) {
return redisTemplate.expire(key, timeout, unit);
}
public Long getExpire(String key) {
return redisTemplate.getExpire(key, TimeUnit.SECONDS);
}
public void set(String key, Object value) {
redisTemplate.opsForValue().set(key, value);
}
public void set(String key, Object value, long timeout, TimeUnit unit) {
redisTemplate.opsForValue().set(key, value, timeout, unit);
}
public Boolean setIfAbsent(String key, Object value, long timeout, TimeUnit unit) {
return redisTemplate.opsForValue().setIfAbsent(key, value, timeout, unit);
}
public Object get(String key) {
return redisTemplate.opsForValue().get(key);
}
public Long increment(String key, long delta) {
return redisTemplate.opsForValue().increment(key, delta);
}
public void hPut(String key, String hashKey, Object value) {
redisTemplate.opsForHash().put(key, hashKey, value);
}
public void hPutAll(String key, Map<String, Object> map) {
redisTemplate.opsForHash().putAll(key, map);
}
public Object hGet(String key, String hashKey) {
return redisTemplate.opsForHash().get(key, hashKey);
}
public Map<Object, Object> hGetAll(String key) {
return redisTemplate.opsForHash().entries(key);
}
public Long hDelete(String key, Object... hashKeys) {
return redisTemplate.opsForHash().delete(key, hashKeys);
}
public Long lPush(String key, Object value) {
return redisTemplate.opsForList().leftPush(key, value);
}
public List<Object> lRange(String key, long start, long end) {
return redisTemplate.opsForList().range(key, start, end);
}
public Object lPop(String key) {
return redisTemplate.opsForList().leftPop(key);
}
public Long sAdd(String key, Object... values) {
return redisTemplate.opsForSet().add(key, values);
}
public Set<Object> sMembers(String key) {
return redisTemplate.opsForSet().members(key);
}
public Boolean sIsMember(String key, Object value) {
return redisTemplate.opsForSet().isMember(key, value);
}
public Boolean zAdd(String key, Object value, double score) {
return redisTemplate.opsForZSet().add(key, value, score);
}
public Set<Object> zRange(String key, long start, long end) {
return redisTemplate.opsForZSet().range(key, start, end);
}
public Set<ZSetOperations.TypedTuple<Object>> zRangeWithScores(String key, long start, long end) {
return redisTemplate.opsForZSet().rangeWithScores(key, start, end);
}
public Double zIncrementScore(String key, Object value, double delta) {
return redisTemplate.opsForZSet().incrementScore(key, value, delta);
}
}
二、🚀 实战应用
1. 分布式锁服务 (DistributedLockService.java)
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.stereotype.Service;
import java.util.Collections;
import java.util.concurrent.TimeUnit;
@Service
public class DistributedLockService {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
private static final String RELEASE_LOCK_SCRIPT =
"if redis.call('get', KEYS[1]) == ARGV[1] then " +
"return redis.call('del', KEYS[1]) " +
"else " +
"return 0 " +
"end";
private static final String LOCK_PREFIX = "lock:";
public Boolean tryLock(String lockKey, String requestId, long expireTime, TimeUnit unit) {
String fullLockKey = LOCK_PREFIX + lockKey;
return redisTemplate.opsForValue().setIfAbsent(fullLockKey, requestId, expireTime, unit);
}
public Boolean releaseLock(String lockKey, String requestId) {
String fullLockKey = LOCK_PREFIX + lockKey;
DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>(RELEASE_LOCK_SCRIPT, Long.class);
Long result = redisTemplate.execute(redisScript, Collections.singletonList(fullLockKey), requestId);
return result != null && result == 1;
}
}
2.缓存实战:缓存穿透/击穿/雪崩解决方案(CacheService.java)
@Service
public class CacheService {
@Autowired
private RedisUtil redisUtil;
private static final String CACHE_PREFIX = "cache:";
private static final String NULL_CACHE = "NULL";
public Product getProductById(Long productId) {
String key = CACHE_PREFIX + "product:" + productId;
Product product = (Product) redisUtil.get(key);
if (product != null) {
if (NULL_CACHE.equals(product)) {
return null;
}
return product;
}
synchronized (this) {
product = (Product) redisUtil.get(key);
if (product != null) {
if (NULL_CACHE.equals(product)) {
return null;
}
return product;
}
product = productRepository.findById(productId).orElse(null);
if (product == null) {
redisUtil.set(key, NULL_CACHE, 60, TimeUnit.SECONDS);
} else {
long expireTime = 1800 + new Random().nextInt(600);
redisUtil.set(key, product, expireTime, TimeUnit.SECONDS);
}
return product;
}
}
}
3. 排行榜服务 (RankingService.java)
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;
import java.util.Set;
@Service
public class RankingService {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
private static final String RANKING_KEY = "leaderboard";
public void updatePlayerScore(String playerId, double score) {
redisTemplate.opsForZSet().add(RANKING_KEY, playerId, score);
}
public Set<ZSetOperations.TypedTuple<Object>> getTopPlayers(int topN) {
return redisTemplate.opsForZSet().reverseRangeWithScores(RANKING_KEY, 0, topN - 1);
}
public Long getPlayerRank(String playerId) {
Long rank = redisTemplate.opsForZSet().reverseRank(RANKING_KEY, playerId);
return rank != null ? rank + 1 : null;
}
public Double incrementPlayerScore(String playerId, double delta) {
return redisTemplate.opsForZSet().incrementScore(RANKING_KEY, playerId, delta);
}
}
四、🧪 测试控制器
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.web.bind.annotation.*;
import java.util.Set;
import java.util.UUID;
@RestController
@RequestMapping("/api/redis")
public class TestController {
@Autowired
private StringOpsService stringOpsService;
@Autowired
private HashOpsService hashOpsService;
@Autowired
private DistributedLockService distributedLockService;
@Autowired
private RankingService rankingService;
@GetMapping("/test-string")
public String testStringOps() {
stringOpsService.setWithExpire("test:key", "Hello Redis!", 10, TimeUnit.MINUTES);
return "String operation test completed.";
}
@GetMapping("/test-lock")
public String testDistributedLock() {
String lockKey = "resource:1";
String requestId = UUID.randomUUID().toString();
boolean locked = distributedLockService.tryLock(lockKey, requestId, 10, TimeUnit.SECONDS);
if (locked) {
try {
Thread.sleep(2000);
return "Lock acquired and operation performed.";
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return "Operation interrupted.";
} finally {
distributedLockService.releaseLock(lockKey, requestId);
}
} else {
return "Failed to acquire lock.";
}
}
@PostMapping("/update-score/{playerId}")
public String updateScore(@PathVariable String playerId, @RequestParam double score) {
rankingService.updatePlayerScore(playerId, score);
return "Score updated for player: " + playerId;
}
@GetMapping("/leaderboard/top/{n}")
public Set<ZSetOperations.TypedTuple<Object>> getTopPlayers(@PathVariable int n) {
return rankingService.getTopPlayers(n);
}
}