Zeelord 2024-08-26 16:56 采纳率: 85.7%
浏览 8
已结题

synchronized,多线程获取到相同的流水号

自己手动编写了一个获取流水号的代码,测试两个线程同时调用接口,得到的流水号是一样的
下面是流水号相关获取方法,日志输出的tNumberMake 也是一样的

public synchronized String getCode(String numberType, String jcjg, String jcff, String gcbh) {
        StringBuilder code = new StringBuilder();
        try {
            List<TNumberMake> numberMakes = list(new QueryWrapper<TNumberMake>().eq("number_type", numberType));
            if (numberMakes.isEmpty()) {
                throw new RuntimeException("未找到对应类型的编号配置");
            }
            TNumberMake tNumberMake = numberMakes.get(0);
            log.debug(JSONUtil.toJsonStr(tNumberMake));
            List<TNumberRulerelation> relations = tNumberRulerelationService.list(new QueryWrapper<TNumberRulerelation>().eq("number_id", tNumberMake.getNumberId()));

            for (TNumberRulerelation relation : relations) {
                if (relation.getRuleName().equals(TNumberMakeConstant.RULE_GCBH)) {
                    code.append(gcbh);
                } else if (relation.getRuleName().equals(TNumberMakeConstant.RULE_JCJJ)) {
                    code.append(jcff);
                } else if (relation.getRuleName().equals(TNumberMakeConstant.RULE_JCFF)) {
                    code.append(jcjg);
                } else if (relation.getRuleName().equals(TNumberMakeConstant.RULE_BANF)) {
                    // 使用 DateTimeFormatter 简化日期格式化
                    String lastTwoDigits = LocalDate.now().format(DateTimeFormatter.ofPattern("yy"));
                    code.append(lastTwoDigits);
                } else if (relation.getRuleName().equals(TNumberMakeConstant.RULE_ZDY)) {
                    code.append(relation.getRuleExpression());
                } else if (relation.getRuleName().equals(TNumberMakeConstant.RULE_LSH2)) {
                    code.append(String.format("%02d", tNumberMake.getSerialNumber()));
                } else if (relation.getRuleName().equals(TNumberMakeConstant.RULE_LSH3)) {
                    code.append(String.format("%03d", tNumberMake.getSerialNumber()));
                } else if (relation.getRuleName().equals(TNumberMakeConstant.RULE_LSH4)) {
                    code.append(String.format("%04d", tNumberMake.getSerialNumber()));
                } else if (relation.getRuleName().equals(TNumberMakeConstant.RULE_LSH5)) {
                    code.append(String.format("%05d", tNumberMake.getSerialNumber()));
                }

                if ("1".equals(relation.getIsConnector())) {
                    code.append("-");
                }
            }

            tNumberMake.setSerialNumber(tNumberMake.getSerialNumber() + 1);
            updateById(tNumberMake);
        } catch (Exception e) {
            log.error("获取编号失败", e);
            throw new RuntimeException("获取编号失败: " + e.getMessage(), e);
        }
        return code.toString();
    }

  • 写回答

2条回答 默认 最新

  • Zeelord 2024-08-27 09:49
    关注

    猜测可能是因为锁的释放时机和事务提交时机导致的,锁是方法执行完释放,事务也是方法执行完才提交,那问题就出在锁刚刚释放,第二个线程立马拿到锁入栈搞偷袭。
    防止脏读就可以解决,可以方法内手动提交事务或者声明事务级别为SERIALIZABLE

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

问题事件

  • 系统已结题 1月24日
  • 已采纳回答 1月16日
  • 创建了问题 8月26日