参考: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>@Autowiredprivate 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,满足需求。
