并发的修改1个字段,集群环境

用了redisson的加锁,锁10秒钟,防重(业务上防止一个用户进行多次插入,只允许插入一条)的select代码在加锁的代码外面,如果存在,就不让执行锁里面的代码。
锁里面的代码:读取某个字段(如起始价格),然后修改最终价格(随机的),插入数据表,在锁的里面执行
目前出现了几笔同一个人的重复数据,起始价格都一样,最终价格不一样
怀疑是锁里面的代码执行的数据库修改并没有随锁的释放提交,导致防重逻辑失效
请问如何规避这种问题?

以下是伪代码
这个是controller,接请求,检查该用户是否在A表插入过记录,没有差如果,执行updateFieldAndInsertRecordConcurrently
//id为用户id
if(!checkIfExisitByUserId(id)) {
    updateFieldAndInsertRecordConcurrently(id);
}

//这个是其他的辅助类的方法
updateFieldAndInsertRecordConcurrently(Integer id) {

    try{
         RLock lock = redisClientManager.getClient().getLock("Activity_Price_Off_midAutumnLock";
        lock.lock(Integer.parseInt("10"), TimeUnit.SECONDS); //redisson的锁,最多锁10s
        
        //从B表读取价格
        BigDecimal currentPrice = getCuurentPrice(); 
        //随机一个价格,减掉
        BigDeciaml randomOffPrice = getRandomOffPrice();
        //最终价格
        BigDecimal resultPrice = currentPrice.subtract(randomOffPrice);
        //插入A记录(起始价格,随机价格,优惠后价格)
        insertARecordByUserId(id, currentPrice, randomOffPrice, resultPrice ) ;
        //更新B表的价格栏位
        updateCurrentPrice(resultPrice);
    }catch(Exception e) {}
    finally {
        lock.unlock();
    }
}


现在A表存在两个用户的记录,比如a1,a2,起始价格(currentPrice栏位都一样),而这是业务不允许的,要求串行

脏数据见图片:三栏的含义分别是:用户,随机价格,优惠后价格

图片描述

阅读 2.8k
1 个回答

代码不贴出来,怎么玩,在怎么也要把伪代码写出来吧
lock.lock(Integer.parseInt("10"), TimeUnit.SECONDS);这句的问题
如果有多个请求过来,比如说有人手贱多点了几次
第一个请求拿到锁后,更新数据,后面的请求会阻塞,并不过直接跳过去,等第一个请求执行完成后释放锁,后续的请求又拿到锁了,所以又执行了
应该是这样一个逻辑就ok了,同时来了多个请求,第一个请求拿到锁执行代码逻辑,后面的请求直接跳过就不会出现你的问题了
应该是你api用错了,用这个boolean tryLock()
类似代码

updateFieldAndInsertRecordConcurrently(Integer id) {

    try{
         RLock lock = redisClientManager.getClient().getLock("Activity_Price_Off_midAutumnLock";
        if(lock.tryLock()){
            //从B表读取价格
            BigDecimal currentPrice = getCuurentPrice(); 
            //随机一个价格,减掉
            BigDeciaml randomOffPrice = getRandomOffPrice();
            //最终价格
            BigDecimal resultPrice = currentPrice.subtract(randomOffPrice);
            //插入A记录(起始价格,随机价格,优惠后价格)
            insertARecordByUserId(id, currentPrice, randomOffPrice, resultPrice ) ;
            //更新B表的价格栏位
            updateCurrentPrice(resultPrice);
        }
    }catch(Exception e) {}
    finally {
        lock.unlock();
    }
}
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题