参考:https://www.cnblogs.com/moxiaotao/p/10829799.html

利用redis分布式锁来实现秒杀功能测试,功能不满足上线需求,只是小测试。
测试源码:redis-test.zip
还需要解决的问题:

  • 用户是否允许多次购买。
  • 如何分辨用户误操作(多次点击)。
  • 如何异步处理订单。
  • 如何处理用户退货。

基础准备

redis安装

  1. docker run -di \
  2. --name=redis \
  3. -p 6379:6379 \
  4. redis

编写并发访问程序

在示例代码中。

分布式锁的实现

方式一,自己编写:

  1. public boolean getLock(String key, String id, int expireTime) {
  2. Boolean aBoolean = redisTemplate.opsForValue().setIfAbsent(key, id, expireTime, TimeUnit.SECONDS);
  3. return Optional.ofNullable(aBoolean).orElse(false);
  4. }
  5. public void releaseLock(String key, String value) {
  6. String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
  7. redisTemplate.execute(new DefaultRedisScript<>(script, Long.class), Collections.singletonList(key), value);
  8. }

方式二:使用 redisson-springboot

  1. <dependency>
  2. <groupId>org.redisson</groupId>
  3. <artifactId>redisson-spring-boot-starter</artifactId>
  4. <version>3.10.1</version>
  5. </dependency>
  6. @Autowired
  7. private RedissonClient redisson ;
  8. //获得分布式锁实例
  9. lock = redisson.getLock(key);
  10. //加锁并且设置自动失效时间15秒
  11. lock.lock(15, TimeUnit.SECONDS);
  12. // 解锁
  13. lock.unlock();

测试

不加锁的情况

性能最好。

  1. // 判断是否还有剩余
  2. if (getValue(PRODUCT_KEY) > 0) {
  3. // 秒单成功
  4. if (redisTemplate.opsForValue().increment(PRODUCT_KEY, (long) -1) >= 0) {
  5. // 记录到数据库,或者队列 异步处理
  6. log.info("success");
  7. } else {
  8. // 撤销
  9. redisTemplate.opsForValue().increment(PRODUCT_KEY, 1);
  10. }
  11. }

加锁的情况

安全,但是会消减性能。

  1. if (getValue(random) > 0) {
  2. if (getLock(KEY_1_LOCK, random, 100)) {
  3. redisTemplate.opsForValue().increment(KEY_1, (long) -1);
  4. releaseLock(KEY_1_LOCK, random);
  5. }
  6. }

127.0.0.1:6379> get key1 “0”

测试多次,最终结果都是0,满足需求。