目标
一行代码调用
安装
redis
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
hutool 工具类
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.16</version>
</dependency>
配置
spring:
data:
redis:
host: xxx
port: 6379
password: xxx
database: x
配置类
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
/**
* 方便获取 Spring IOC 实例
*
* @author jason
*/
@Configuration
@Import(cn.hutool.extra.spring.SpringUtil.class)
public class BeanConf {
}
工具类
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Component;
/**
* Redis 操作工具类
*
* @author jason
*/
@Slf4j
@Component
public class RedisUtil {
@Autowired
private StringRedisTemplate stringRedisTemplate;
public static RedisUtil instance() {
return SpringUtil.getBean(RedisUtil.class);
}
/**
* set
*/
public static void set(String key, Object value) {
instance().stringRedisTemplate.opsForValue().set(key, StrUtil.toStringOrNull(value));
}
/**
* get
*/
public static String get(String key) {
return instance().stringRedisTemplate.opsForValue().get(key);
}
/**
* decr 扣减
*/
public static Long decrement(String key) {
return instance().stringRedisTemplate.opsForValue().decrement(key);
}
/**
* incr 增加
*/
public static Long increment(String key) {
return instance().stringRedisTemplate.opsForValue().increment(key);
}
/**
* 无锁:decr 扣减 + incr 回滚
*/
public static boolean decrementCouponId(String couponId) {
// 库存 - 1
Long decrementNum = RedisUtil.decrement(couponId);
log.info("优惠券扣减后库存:{}", decrementNum);
// 库存 + 1
if (decrementNum < 0) {
Long incrementNum = RedisUtil.increment(couponId);
log.info("优惠券回滚后库存:{}", incrementNum);
return false;
}
return true;
}
/**
* 无锁:lua + decr 扣减
*/
public static Boolean luaDecrCid(String couponId) {
// Lua 脚本
String script = """
local couponId = KEYS[1]
local value = tonumber(redis.call('GET', couponId))
if value > 0 then
redis.call('DECR', couponId)
return true
else
return false
end
""";
DefaultRedisScript<Boolean> redisScript = new DefaultRedisScript<>(script, Boolean.class);
return instance().stringRedisTemplate.execute(redisScript, CollectionUtil.newArrayList(couponId));
}
/**
* 无锁:lua + decr 扣减
*
* 限制:1个用户,1张券
*/
public static Boolean luaUserCid(String userId, String couponId) {
// Lua 脚本
String script = """
local userId = KEYS[1]
local couponId = KEYS[2]
local isUserSuccess = redis.call('GET', userId)
local value = tonumber(redis.call('GET', couponId))
if isUserSuccess ~= "true" and value > 0 then
redis.call('DECR', couponId)
redis.call('SET', userId, "true")
return true
else
return false
end
""";
DefaultRedisScript<Boolean> redisScript = new DefaultRedisScript<>(script, Boolean.class);
return instance().stringRedisTemplate.execute(redisScript, CollectionUtil.newArrayList(userId, couponId));
}
}