public void safedUnLock(String key, String val) {
String luaScript = “local in = ARGV[1] local curr=redis.call(‘get’, KEYS[1]) if in==curr then redis.call(‘del’, KEYS[1]) end return ‘OK’”";
RedisScript redisScript = RedisScript.of(luaScript);
redisTemplate.execute(redisScript, Collections.singletonList(key), Collections.singleton(val));
}
我们通过LUA脚本来实现安全地解锁。
实现安全的库存校验
如果我们对于并发有比较深入的了解的话,会发现想 get and compare/ read and save 等操作,都是非原子性的。如果要实现原子性,我们也可以借助LUA脚本来实现。
但就我们这个例子中,由于抢购活动一单只能下1瓶,因此可以不用基于LUA脚本实现而是基于redis本身的原子性。原因在于:
// redis会返回操作之后的结果,这个过程是原子性的
Long currStock = redisTemplate.opsForHash().increment(“key”, “stock”, -1);
发现没有,代码中的库存校验完全是“画蛇添足”。
改进之后的代码
经过以上的分析之后,我们决定新建一个DistributedLocker类专门用于处理分布式锁。
public SeckillActivityRequestVO seckillHandle(SeckillActivityRequestVO request) {
SeckillActivityRequestVO response;
String key = “key:” + request.getSeckillId();
String val = UUID.randomUUID().toString();
try {
Boolean lockFlag = distributedLocker.lock(key, val, 10, TimeUnit.SEC