• redis分布式秒杀锁


    在这里插入图片描述

    -- 获取锁标识,是否与当前线程一致?
    if(redis.call('get', KEYS[1]) == ARGV[1]) then
        -- 一致,删除
        return redis.call('del', KEYS[1])
    end
    -- 不一致,直接返回
    return 0
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在这里插入图片描述

    package com.platform.lock;
    
    public interface ILock {
    
        /**
         * 获取锁
         * @param timeoutSec
         * @return
         */
        public boolean tryLock(long timeoutSec);
    
        /**
         * 锁标识、释放锁
         */
        public void unlock();
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    在这里插入图片描述

    package com.platform.lock;
    
    import cn.hutool.core.lang.UUID;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.core.io.ClassPathResource;
    import org.springframework.data.redis.core.StringRedisTemplate;
    import org.springframework.data.redis.core.script.DefaultRedisScript;
    import org.springframework.stereotype.Service;
    
    import java.util.Collections;
    import java.util.concurrent.TimeUnit;
    
    /**
     * redis的分布式锁
     * 实现ILock接口
     */
    public class SimpleRedisLock implements ILock {
    
        // 不同的业务有不同的锁名称
        private String name;
    
        private StringRedisTemplate stringRedisTemplate;
        private static final String KEY_PREFIX = "tryLock:";
        private static final String ID_PREFIX = UUID.randomUUID().toString(true) + "-";
        // DefaultRedisScript,
        private static final DefaultRedisScript UNLOCK_SCRIPT;
    
        public SimpleRedisLock(String name, StringRedisTemplate stringRedisTemplate) {
            this.name = name;
            this.stringRedisTemplate = stringRedisTemplate;
        }
    
        // 初始化 UNLOCK_SCRIPT,用静态代码块的方式,一加载SimpleRedisLock有会加载unlock.lua
        // 避免每次调unLock() 才去加载,提升性能!!!
        static {
            UNLOCK_SCRIPT = new DefaultRedisScript<>();
            // setLocation() 设置脚本位置
            UNLOCK_SCRIPT.setLocation(new ClassPathResource("unlock.lua"));
            // 返回值类型
            UNLOCK_SCRIPT.setResultType(Long.class);
        }
    
        /**
         * 获取锁
         */
        @Override
        public boolean tryLock(long timeoutSec) {
            // 获取线程标示
            String threadId = ID_PREFIX + Thread.currentThread().getId();
            // 获取锁
            // set lock thread1 nx ex 10
            // nx : setIfAbsent(如果不存在) , ex : timeoutSec(秒)
            Boolean success = stringRedisTemplate.opsForValue()
                    .setIfAbsent(KEY_PREFIX + name, threadId, timeoutSec, TimeUnit.SECONDS);
            // 自动拆箱(Boolean -> boolean)!!!可能有风险
            return Boolean.TRUE.equals(success);
        }
    
        /**
         * 解决判断(锁标识、释放锁)这两个动作,之间产生阻塞!!!
         * JVM的 FULL GC
         * 要让这两个动作具有原子性
         */
        @Override
        public void unlock() {
            // 调用lua脚本
            stringRedisTemplate.execute(
                    UNLOCK_SCRIPT,
                    Collections.singletonList(KEY_PREFIX + name),
                    ID_PREFIX + Thread.currentThread().getId());
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73

    在这里插入图片描述

        @PostMapping("/cancelPublicBenefit")
        @CheckRepeatCommit
        public RestResponse cancelPublicBenefit(@LoginUser MallUserEntity loginUser, @RequestBody MallPublicBenefitEntity publicBenefitEntity) {
    
            String key = PUBLIC_BENEFIT_TEAM_LOCK_FLAG + publicBenefitEntity.getId();
            RestResponse restResponse = null;
    
            SimpleRedisLock simpleRedisLock = new SimpleRedisLock(key,stringRedisTemplate);
            try {
                if (simpleRedisLock.tryLock(15)) {
                    // 成功获取锁,执行业务逻辑
                    restResponse = mallPublicBenefitService.cancelPublicBenefit(loginUser, publicBenefitEntity);
                } else {
                    // 获取锁失败,处理失败逻辑
                    throw new BusinessException("服务器繁忙!");
                }
            } finally {
                simpleRedisLock.unlock();
            }
    
            return restResponse;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    在这里插入图片描述

  • 相关阅读:
    POI和EasyExcel
    与社交媒体结合:视频直播美颜sdk在社交平台上的应用
    策略模式调优(多Oss存储导致代码冗余的问题)
    八大排序之堆排序
    【python学习】基础篇-常用模块-multiprocessing模块:多进程
    python pip notes
    Verilog的时间系统任务----$time、$stime、$realtime
    第十二章·装饰模式
    UI自动化测试神器Playwright(Java版)(保存登录cookie,解决免登录)
    运行ps显示msvcp140.dll丢失怎么恢复?msvcp140.dll快速解决的4个不同方法
  • 原文地址:https://blog.csdn.net/weixin_55181056/article/details/133633987