387 lines
9.6 KiB
Java
387 lines
9.6 KiB
Java
package com.org.flashsalesystem.service;
|
||
|
||
import lombok.extern.slf4j.Slf4j;
|
||
import org.springframework.beans.factory.annotation.Autowired;
|
||
import org.springframework.beans.factory.annotation.Qualifier;
|
||
import org.springframework.data.redis.core.RedisTemplate;
|
||
import org.springframework.data.redis.core.script.DefaultRedisScript;
|
||
import org.springframework.stereotype.Service;
|
||
|
||
import java.util.*;
|
||
import java.util.concurrent.TimeUnit;
|
||
|
||
/**
|
||
* Redis服务类
|
||
* 封装Redis的各种操作,包括五种数据类型的应用
|
||
*/
|
||
@Service
|
||
@Slf4j
|
||
public class RedisService {
|
||
|
||
@Autowired
|
||
private RedisTemplate<String, Object> redisTemplate;
|
||
|
||
@Autowired
|
||
@Qualifier("customStringRedisTemplate")
|
||
private RedisTemplate<String, String> stringRedisTemplate;
|
||
|
||
@Autowired
|
||
private DefaultRedisScript<Long> flashSaleScript;
|
||
|
||
@Autowired
|
||
private DefaultRedisScript<String> lockScript;
|
||
|
||
@Autowired
|
||
private DefaultRedisScript<Long> unlockScript;
|
||
|
||
// ========== String类型操作 ==========
|
||
|
||
/**
|
||
* 设置字符串值
|
||
*/
|
||
public void set(String key, Object value) {
|
||
redisTemplate.opsForValue().set(key, value);
|
||
}
|
||
|
||
/**
|
||
* 设置纯字符串值(用于Lua脚本兼容)
|
||
*/
|
||
public void setString(String key, String value) {
|
||
stringRedisTemplate.opsForValue().set(key, value);
|
||
}
|
||
|
||
/**
|
||
* 设置字符串值并指定过期时间
|
||
*/
|
||
public void set(String key, Object value, long timeout, TimeUnit unit) {
|
||
redisTemplate.opsForValue().set(key, value, timeout, unit);
|
||
}
|
||
|
||
/**
|
||
* 获取字符串值
|
||
*/
|
||
public Object get(String key) {
|
||
return redisTemplate.opsForValue().get(key);
|
||
}
|
||
|
||
/**
|
||
* 安全获取字符串值
|
||
*/
|
||
public String getString(String key) {
|
||
return stringRedisTemplate.opsForValue().get(key);
|
||
}
|
||
|
||
/**
|
||
* 原子递增
|
||
*/
|
||
public Long incr(String key) {
|
||
return redisTemplate.opsForValue().increment(key);
|
||
}
|
||
|
||
/**
|
||
* 原子递增指定步长
|
||
*/
|
||
public Long incrBy(String key, long delta) {
|
||
return redisTemplate.opsForValue().increment(key, delta);
|
||
}
|
||
|
||
/**
|
||
* 原子递减
|
||
*/
|
||
public Long decr(String key) {
|
||
return redisTemplate.opsForValue().decrement(key);
|
||
}
|
||
|
||
/**
|
||
* 原子递减指定步长
|
||
*/
|
||
public Long decrBy(String key, long delta) {
|
||
return redisTemplate.opsForValue().decrement(key, delta);
|
||
}
|
||
|
||
/**
|
||
* 设置键值,仅当键不存在时
|
||
*/
|
||
public Boolean setNx(String key, Object value) {
|
||
return redisTemplate.opsForValue().setIfAbsent(key, value);
|
||
}
|
||
|
||
/**
|
||
* 设置键值和过期时间,仅当键不存在时
|
||
*/
|
||
public Boolean setNx(String key, Object value, long timeout, TimeUnit unit) {
|
||
return redisTemplate.opsForValue().setIfAbsent(key, value, timeout, unit);
|
||
}
|
||
|
||
// ========== Hash类型操作 ==========
|
||
|
||
/**
|
||
* 设置Hash字段值
|
||
*/
|
||
public void hSet(String key, String field, Object value) {
|
||
redisTemplate.opsForHash().put(key, field, value);
|
||
}
|
||
|
||
/**
|
||
* 获取Hash字段值
|
||
*/
|
||
public Object hGet(String key, String field) {
|
||
return redisTemplate.opsForHash().get(key, field);
|
||
}
|
||
|
||
/**
|
||
* 批量设置Hash字段
|
||
*/
|
||
public void hMSet(String key, Map<String, Object> map) {
|
||
redisTemplate.opsForHash().putAll(key, map);
|
||
}
|
||
|
||
/**
|
||
* 批量获取Hash字段值
|
||
*/
|
||
public List<Object> hMGet(String key, Collection<Object> fields) {
|
||
return redisTemplate.opsForHash().multiGet(key, fields);
|
||
}
|
||
|
||
/**
|
||
* 获取Hash所有字段和值
|
||
*/
|
||
public Map<Object, Object> hGetAll(String key) {
|
||
return redisTemplate.opsForHash().entries(key);
|
||
}
|
||
|
||
/**
|
||
* 删除Hash字段
|
||
*/
|
||
public Long hDel(String key, Object... fields) {
|
||
return redisTemplate.opsForHash().delete(key, fields);
|
||
}
|
||
|
||
/**
|
||
* 检查Hash字段是否存在
|
||
*/
|
||
public Boolean hExists(String key, String field) {
|
||
return redisTemplate.opsForHash().hasKey(key, field);
|
||
}
|
||
|
||
/**
|
||
* Hash字段值递增
|
||
*/
|
||
public Long hIncrBy(String key, String field, long delta) {
|
||
return redisTemplate.opsForHash().increment(key, field, delta);
|
||
}
|
||
|
||
/**
|
||
* 获取Hash长度
|
||
*/
|
||
public Long hLen(String key) {
|
||
return redisTemplate.opsForHash().size(key);
|
||
}
|
||
|
||
// ========== List类型操作 ==========
|
||
|
||
/**
|
||
* 从左侧推入元素
|
||
*/
|
||
public Long lPush(String key, Object... values) {
|
||
return redisTemplate.opsForList().leftPushAll(key, values);
|
||
}
|
||
|
||
/**
|
||
* 从右侧推入元素
|
||
*/
|
||
public Long rPush(String key, Object... values) {
|
||
return redisTemplate.opsForList().rightPushAll(key, values);
|
||
}
|
||
|
||
/**
|
||
* 从左侧弹出元素
|
||
*/
|
||
public Object lPop(String key) {
|
||
return redisTemplate.opsForList().leftPop(key);
|
||
}
|
||
|
||
/**
|
||
* 从右侧弹出元素
|
||
*/
|
||
public Object rPop(String key) {
|
||
return redisTemplate.opsForList().rightPop(key);
|
||
}
|
||
|
||
/**
|
||
* 获取列表长度
|
||
*/
|
||
public Long lLen(String key) {
|
||
return redisTemplate.opsForList().size(key);
|
||
}
|
||
|
||
/**
|
||
* 获取列表指定范围的元素
|
||
*/
|
||
public List<Object> lRange(String key, long start, long end) {
|
||
return redisTemplate.opsForList().range(key, start, end);
|
||
}
|
||
|
||
// ========== Set类型操作 ==========
|
||
|
||
/**
|
||
* 添加元素到集合
|
||
*/
|
||
public Long sAdd(String key, Object... values) {
|
||
return redisTemplate.opsForSet().add(key, values);
|
||
}
|
||
|
||
/**
|
||
* 从集合中移除元素
|
||
*/
|
||
public Long sRem(String key, Object... values) {
|
||
return redisTemplate.opsForSet().remove(key, values);
|
||
}
|
||
|
||
/**
|
||
* 检查元素是否在集合中
|
||
*/
|
||
public Boolean sIsMember(String key, Object value) {
|
||
return redisTemplate.opsForSet().isMember(key, value);
|
||
}
|
||
|
||
/**
|
||
* 获取集合所有元素
|
||
*/
|
||
public Set<Object> sMembers(String key) {
|
||
return redisTemplate.opsForSet().members(key);
|
||
}
|
||
|
||
/**
|
||
* 获取集合大小
|
||
*/
|
||
public Long sCard(String key) {
|
||
return redisTemplate.opsForSet().size(key);
|
||
}
|
||
|
||
// ========== ZSet类型操作 ==========
|
||
|
||
/**
|
||
* 添加元素到有序集合
|
||
*/
|
||
public Boolean zAdd(String key, Object value, double score) {
|
||
return redisTemplate.opsForZSet().add(key, value, score);
|
||
}
|
||
|
||
/**
|
||
* 从有序集合中移除元素
|
||
*/
|
||
public Long zRem(String key, Object... values) {
|
||
return redisTemplate.opsForZSet().remove(key, values);
|
||
}
|
||
|
||
/**
|
||
* 获取有序集合指定范围的元素(按分数排序)
|
||
*/
|
||
public Set<Object> zRange(String key, long start, long end) {
|
||
return redisTemplate.opsForZSet().range(key, start, end);
|
||
}
|
||
|
||
/**
|
||
* 获取有序集合指定范围的元素(按分数倒序)
|
||
*/
|
||
public Set<Object> zRevRange(String key, long start, long end) {
|
||
return redisTemplate.opsForZSet().reverseRange(key, start, end);
|
||
}
|
||
|
||
/**
|
||
* 增加有序集合元素的分数
|
||
*/
|
||
public Double zIncrBy(String key, Object value, double delta) {
|
||
return redisTemplate.opsForZSet().incrementScore(key, value, delta);
|
||
}
|
||
|
||
/**
|
||
* 获取有序集合大小
|
||
*/
|
||
public Long zCard(String key) {
|
||
return redisTemplate.opsForZSet().zCard(key);
|
||
}
|
||
|
||
// ========== 通用操作 ==========
|
||
|
||
/**
|
||
* 删除键
|
||
*/
|
||
public Boolean delete(String key) {
|
||
return redisTemplate.delete(key);
|
||
}
|
||
|
||
/**
|
||
* 批量删除键
|
||
*/
|
||
public Long delete(Collection<String> keys) {
|
||
return redisTemplate.delete(keys);
|
||
}
|
||
|
||
/**
|
||
* 检查键是否存在
|
||
*/
|
||
public Boolean exists(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);
|
||
}
|
||
|
||
// ========== Lua脚本操作 ==========
|
||
|
||
/**
|
||
* 执行秒杀脚本
|
||
*/
|
||
public Long executeFlashSaleScript(String stockKey, int quantity) {
|
||
log.info("执行秒杀脚本: stockKey={}, quantity={}", stockKey, quantity);
|
||
|
||
try {
|
||
Long result = stringRedisTemplate.execute(flashSaleScript, Collections.singletonList(stockKey),
|
||
String.valueOf(quantity));
|
||
log.info("秒杀脚本执行结果: result={}", result);
|
||
|
||
return result;
|
||
} catch (Exception e) {
|
||
log.error("执行秒杀脚本异常: stockKey={}, quantity={}", stockKey, quantity, e);
|
||
throw e;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 执行分布式锁脚本
|
||
*/
|
||
public String executeLockScript(String lockKey, String lockValue, int expireSeconds) {
|
||
return redisTemplate.execute(lockScript, Collections.singletonList(lockKey), lockValue,
|
||
String.valueOf(expireSeconds));
|
||
}
|
||
|
||
/**
|
||
* 执行释放锁脚本
|
||
*/
|
||
public Long executeUnlockScript(String lockKey, String lockValue) {
|
||
return redisTemplate.execute(unlockScript, Collections.singletonList(lockKey), lockValue);
|
||
}
|
||
|
||
// ========== 发布订阅操作 ==========
|
||
|
||
/**
|
||
* 发布消息
|
||
*/
|
||
public void publish(String channel, Object message) {
|
||
redisTemplate.convertAndSend(channel, message);
|
||
}
|
||
}
|