• redis分布式锁


    用于用户重复注册, 点击过快,有可能会注册相同的手机号问题。
    在这里插入图片描述
    给用户手机号枷锁一分钟时间,判断相同的手机号。
    判断下面这块代码执行时间是否超过一分钟时间,
    不论超没超过 都会释放锁,
    下个同样的手机号再次注册,
    都得等到代码执行完毕后 (或者是一分钟后)才能进行注册,
    防止有两个相同的手机号,两个线程,查询数据库都没存在,而注册了两次,(需要一个线程代码执行完毕后才会增加)

    在这里插入图片描述
    业务代码

     /**
         * 商户注册
         *
         * @param req
         * @return
         */
        @Transactional(rollbackFor = Exception.class)
        @Override
        public BaseMerchantInfoResp merRegister(MerRegisterReq req) {
            log.info("BaseMerchantInfoServiceImpl.merRegister; 商户注册开始; req:{}", JSON.toJSONString(req));
            Optional opLock = Optional.empty();
            try {
                opLock = redisLockUtils.tryLock(req.getPhone(), BasicConstants.CACHE_TIME_1, TimeUnit.MINUTES);
                opLock.orElseThrow(() -> new BusinessException(BasicResultCode.OPERATE_FREQUENTLY));
                //1. 判断用户是否存在
                BaseMerchantInfo merchantInfo = baseMerchantInfoMapper.selectByPhone(EncryptUtils.encryptPhoneIdCard(req.getPhone()));
                if (merchantInfo != null) {
                    throw new BusinessException(BaseMerchantResultCode.MERCHANT_EXISTS);
                }
                //2. 创建账号
                MerRegisterDTO merRegisterDTO = BeanUtil.copyBean(req, MerRegisterDTO.class);
                PlatformAccountDTO accountDTO = platformAccountExport.merRegister(merRegisterDTO);
                //3. 创建商户
                BaseMerchantInfo baseMerchantInfo = this.buildMerchant(accountDTO);
                //4. 入库
                baseMerchantInfoMapper.insert(baseMerchantInfo);
                log.info("BaseMerchantInfoServiceImpl.merRegister ; 商户创建成功, info:{}", JSON.toJSONString(baseMerchantInfo));
                return BeanUtil.copyBean(baseMerchantInfo, BaseMerchantInfoResp.class);
            } catch (BusinessException bus) {
                throw bus;
            } catch (Exception exception) {
            	//需要抛出异常,否则事务不会生效
               throw exception;
                log.info("BaseMerchantInfoServiceImpl.merRegister");
            } finally {
                redisLockUtils.unLock(opLock);
            }
    
            return null;
        }
    
    • 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

    工具类

    import com.first.pet.exception.BusinessException;
    import lombok.extern.slf4j.Slf4j;
    import org.redisson.api.RLock;
    import org.redisson.api.RedissonClient;
    import org.springframework.stereotype.Component;
    
    import javax.annotation.Resource;
    import java.util.Optional;
    import java.util.concurrent.TimeUnit;
    import java.util.concurrent.locks.Lock;
    
    /**
     * 描述:
     * redis分布式锁工具类
     * 统一提供两种加锁方法
     * - 阻塞锁,会阻塞到获取锁
     * - 非阻塞锁,未获取到锁会直接返回
     * 解锁请直接调用lock.unLock方法
     *
     * @author zhaofeng
     * @date 2023-08-29
     */
    @Component
    @Slf4j
    public class RedisLockUtils {
    
        /**
         * redisson客户端
         */
        @Resource
        private RedissonClient redissonClient;
    
        /**
         * 阻塞获取锁
         * 加锁成功返回optional容器,容器中为Lock对象,加锁失败返回空容器
         *
         * @param key
         * @param time
         * @param timeUnit
         * @return
         */
        public Optional lock(String key, long time, TimeUnit timeUnit) {
            RLock lock = redissonClient.getLock(key);
            try {
                lock.lock(time, timeUnit);
                log.info("加锁成功,key:{},time:{},timeUnit:{}", key, time, timeUnit);
                return Optional.of(lock);
            } catch (Exception exception) {
                log.info("加锁失败,key:{}", key, exception);
                return Optional.empty();
            }
        }
    
        /**
         * 获取锁,非阻塞
         * 加锁成功返回optional容器,容器中为Lock对象,加锁失败返回空容器
         *
         * @param key
         * @param time
         * @param timeUnit
         * @return Optional
         */
        public Optional tryLock(String key, long time, TimeUnit timeUnit) {
            RLock lock = redissonClient.getLock(key);
            try {
                boolean lockResult = lock.tryLock(time, timeUnit);
                log.info("加锁结束, key:{},time:{},timeUnit:{},加锁结果:{}", key, time, timeUnit, lockResult);
                return lockResult ? Optional.of(lock) : Optional.empty();
            } catch (Exception exception) {
                log.info("加锁失败,key:{}", key, exception);
                return Optional.empty();
            }
        }
    
        /**
         * 解锁
         * optional不为空时执行解锁操作
         *
         * @return
         */
        public void unLock(Optional optional) throws BusinessException {
            optional.ifPresent(Lock::unlock);
        }
    }
    
    
    • 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
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85

    依赖

       
            
                org.redisson
                redisson-spring-boot-starter
                3.13.6
            
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    这辈子坚持与不坚持都不可怕,怕的是独自走在坚持的道路上。。

  • 相关阅读:
    单商户商城系统功能拆解30—营销中心—积分签到
    MySQL之函数
    2020最新Java常见面试题及答案
    (开源)批量更新(替换)文本文件中的指定字符串
    常用docker命令 docker_cmd_sheet
    【OS】第二章 进程
    2022年0630-Com.Java.Basis第一课《Java的入门程序》
    【原创】分布式之一行代码解决缓存击穿问题
    C#图片批量下载Demo
    数据链路层实验(以太网帧格式、交换机MAC地址表、广播风暴、生成树协议STP、端口聚合)
  • 原文地址:https://blog.csdn.net/taiguolaotu/article/details/133160275