参考:https://www.cnblogs.com/moxiaotao/p/10829799.html
利用redis分布式锁来实现秒杀功能测试,功能不满足上线需求,只是小测试。
测试源码:redis-test.zip
还需要解决的问题:
- 用户是否允许多次购买。
- 如何分辨用户误操作(多次点击)。
- 如何异步处理订单。
- 如何处理用户退货。
基础准备
redis安装
docker run -di \
--name=redis \
-p 6379:6379 \
redis
编写并发访问程序
在示例代码中。
分布式锁的实现
方式一,自己编写:
public boolean getLock(String key, String id, int expireTime) {
Boolean aBoolean = redisTemplate.opsForValue().setIfAbsent(key, id, expireTime, TimeUnit.SECONDS);
return Optional.ofNullable(aBoolean).orElse(false);
}
public void releaseLock(String key, String value) {
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
redisTemplate.execute(new DefaultRedisScript<>(script, Long.class), Collections.singletonList(key), value);
}
方式二:使用 redisson-springboot
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>3.10.1</version>
</dependency>
@Autowired
private RedissonClient redisson ;
//获得分布式锁实例
lock = redisson.getLock(key);
//加锁并且设置自动失效时间15秒
lock.lock(15, TimeUnit.SECONDS);
// 解锁
lock.unlock();
测试
不加锁的情况
性能最好。
// 判断是否还有剩余
if (getValue(PRODUCT_KEY) > 0) {
// 秒单成功
if (redisTemplate.opsForValue().increment(PRODUCT_KEY, (long) -1) >= 0) {
// 记录到数据库,或者队列 异步处理
log.info("success");
} else {
// 撤销
redisTemplate.opsForValue().increment(PRODUCT_KEY, 1);
}
}
加锁的情况
安全,但是会消减性能。
if (getValue(random) > 0) {
if (getLock(KEY_1_LOCK, random, 100)) {
redisTemplate.opsForValue().increment(KEY_1, (long) -1);
releaseLock(KEY_1_LOCK, random);
}
}
127.0.0.1:6379> get key1 “0”
测试多次,最终结果都是0,满足需求。