lua 脚本保证并发的原子一直性
package com.example.testdocker.controller;
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.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Arrays;
import java.util.Collections;
@RestController
public class Tx {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@GetMapping("/OrderBy")
public String OrderBy(){
String script =
"""
local lockKey = KEYS[1]
local lockTimeout = (ARGV[2])
-- 尝试获取锁
if redis.call('set', lockKey, 1, 'NX', 'PX', lockTimeout) then
local count_str = redis.call('GET', KEYS[2])
local bycount = tonumber(redis.call('GET', 'bycount'))
local count = tonumber(count_str)
if count and count > 0 then
redis.call('SET', KEYS[2], tostring(count - 1))
redis.call('SET', 'bycount',tostring(bycount + 1))
redis.call('DEL', lockKey) -- 操作完成后释放锁
return count -- 成功减少库存
else
redis.call('DEL', lockKey) -- 操作完成后释放锁
return -1 -- 库存不足
end
else
-- 获取锁失败,说明有其他客户端正在操作,直接返回失败
return -2 -- 锁定中,重试
end
""";
String[] keys = {"lock","order",};
Long count = redisTemplate.execute(new DefaultRedisScript<>(script, Long.class), Arrays.asList(keys),"lock",1000L);
System.out.println("库存剩余:"+count);
//getOrder();
return "库存剩余 "+count;
}
@GetMapping("/getOrder")
public String getOrder(){
String script = "return redis.call('GET', KEYS[1])";
Long count = redisTemplate.execute(new DefaultRedisScript<>(script, Long.class), Collections.singletonList("order"));
System.out.println("查询订单数 "+count);
return "查询订单数 "+count;
}
@GetMapping("/setOrder")
public String setOrder(Integer count){
String script =
"""
redis.call('SET', KEYS[1], ARGV[1])
redis.call('SET', 'bycount', 0)
local count = redis.call('GET', KEYS[1])
return count
""";
Long res = redisTemplate.execute(new DefaultRedisScript<>(script, Long.class), Collections.singletonList("order"),count);
return "设置订单数 "+res;
}
}