数据入库时,为什么要用到redis分布式锁?

在业务开发中遇到一个场景,测试人员和我同时点新增某记录时,库里出现了一模一样的数据,实际上,应该按照需求来说,该记录的中文名称应该要不一样。(该记录必须要有中文名称,并且要按照一定规则进行拼接,所以同一页面被多个人打开时,同时操作,会出现拼接的中文名不唯一)

需求:点击新增时,自动为该记录按照规则命名中文名称。

实现:查询上一条该记录的同类,获取同类名称,然后按照规则,命名新增的记录,最后插入记录。

异常:该页面两人及以上同时操作时,点击新增记录,导致出现同名的记录。

解决:加redis分布式锁。

redis分布式锁实现工具类

 /**
     * 分布式锁实现
     *
     * @param lockName   锁名称
     * @param businessId 业务ID
     * @param handle     业务处理
     */
    @Transactional(rollbackFor = Exception.class)
    public void tryLockException(String lockName, Object businessId, VoidHandle handle) {
        RLock rLock = getLock(lockName, businessId);
        if (!rLock.tryLock()) {
            log.error("Acquire a distributed lock, lockName: [{}], businessId: [{}] fail, will throws runtime exception", lockName, businessId);
            throw new RuntimeException("Acquire a distributed lock");
        }

        try {
            log.debug("Acquire a distributed lock, lockName: [{}], businessId: [{}] success", lockName, businessId);
            handle.execute();
        } finally {
            rLock.unlock();
        }
    }

    /**
     * 获取锁
     *
     * @param lockName
     * @param businessId
     * @return
     */
    private RLock getLock(String lockName, Object businessId) {
        if (StrUtil.isBlank(lockName)) {
            throw new RuntimeException("distributed lock key is blank");
        }
        if (Objects.isNull(businessId)) {
            throw new RuntimeException("business ID is null");
        }

        String lockKey = lockName + businessId.toString();
        return redissonClient.getLock(lockKey);
    }

业务实现

service实现层

    @Override
    @Transactional(rollbackFor = {Exception.class, RuntimeException.class})
    public Boolean add(InsertVO insertVo) {
        //bean转换
        Test test= OrikaBeanUtil.map(insertVo, Test.class);
        //分布式实现 用部门id做businessId
        redissonLock.tryLockException("insert:", insertVo.getDepartmentId(), () -> {
            infoManager.insert(test);
        });
        return true;
    }

manager实现层(DAO层)

    @Override
    public Long insert(Test test) {
        //获取上一次相关的数据 
        Test testInfo = getLastInfo(test);
        //设置名称
        test.setName(Objects.isNull(testInfo ) || StrUtil.isBlank(testInfo .getName()) ? NameUtil.INIT_NAME : NameUtil.getNextName(testInfo .getName()));
        return mapper.insert(test);
    }

总结:加上该锁后,多人操作时,会去判断是否有相同记录是否正在插入中(根据部门id或其他作为判断),保证数据不会重复。

所以有遇到相同情况:数据入库时,需要查询以前数据作为依据再入库,但多人操作时发生数据重复入库问题,可以考虑使用锁去解决,我这里是使用redis锁进行解决的。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
在Spring Boot中实现Redis分布式可以通过以下步骤: 1. 添加Redis依赖:在`pom.xml`文件中添加Redis的依赖,例如: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> ``` 2. 配置Redis连接信息:在`application.properties`或`application.yml`文件中配置Redis连接信息,例如: ```properties spring.redis.host=127.0.0.1 spring.redis.port=6379 ``` 3. 创建Redis分布式实现类:创建一个实现了分布式接口的类,例如`RedisDistributedLock`,在该类中注入`StringRedisTemplate`用于操作Redis。 4. 实现加方法:在`RedisDistributedLock`类中实现加方法,可以使用Redis的`setnx`命令来进行加操作,例如: ```java public boolean lock(String key, String value, long expireTime) { Boolean success = redisTemplate.opsForValue().setIfAbsent(key, value, expireTime, TimeUnit.MILLISECONDS); return success != null && success; } ``` 5. 实现释放方法:在`RedisDistributedLock`类中实现释放方法,使用Redis的`del`命令来删除对应的键,例如: ```java public boolean unlock(String key) { return redisTemplate.delete(key); } ``` 6. 在业务代码中使用分布式:在需要加的代码块前后调用加和释放方法,例如: ```java @Autowired private RedisDistributedLock redisDistributedLock; public void doSomethingWithLock() { String lockKey = "my-lock"; String lockValue = UUID.randomUUID().toString(); long expireTime = 10000; // 过期间,单位为毫秒 try { boolean locked = redisDistributedLock.lock(lockKey, lockValue, expireTime); if (locked) { // 执行业务逻辑 } else { // 获取失败,可以进行重试或处理其他逻辑 } } finally { redisDistributedLock.unlock(lockKey); } } ``` 通过以上步骤,就可以在Spring Boot中实现Redis分布式。注意在使用分布式需要考虑的粒度和超处理等问题,以确保分布式的正确使用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值