编号根据规则自增生成,及spring事务和锁

1、 背景

需要根据一些规则来生成自增编号,比如:95JS0001,950002
95JS是固定的,而后缀的0001的长度也是可配置的,因为有一张表来进行维护


CREATE TABLE `number_control` (
  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
  `number_category` varchar(5) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '编号类别',
  `number_type` char(2) COLLATE utf8mb4_general_ci DEFAULT '0' COMMENT '0为微机编号,1为人工编号',
  `is_department_number` char(2) COLLATE utf8mb4_general_ci DEFAULT '1' COMMENT '是否开启单位号,默认开启',
  `project_num` char(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '项目号',
  `is_year` char(2) COLLATE utf8mb4_general_ci DEFAULT '1' COMMENT '是否开启年份,默认开启',
  `is_month` char(2) COLLATE utf8mb4_general_ci DEFAULT '1' COMMENT '是否开启月份,默认开启',
  `divide_sign` char(5) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '分隔符号',
  `digit` int DEFAULT '1' COMMENT '位数,默认为1',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2181 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='编号管理表';

为了方便编号的查询,于是又维护另一张表来存储生成编号的进度

CREATE TABLE `generate_number` (
  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
  `prefix` varchar(100) DEFAULT NULL COMMENT '前缀,根据编号规则生成的前缀',
  `number` bigint DEFAULT '1' COMMENT '记录生成的号码',
  `number_category` char(2) DEFAULT NULL COMMENT '编号类别',
  `digit` int DEFAULT NULL COMMENT '位数'
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='记录编号生成表';

因为要求编号必须连续且自增,所以必然要使用到锁,这里使用的是ReentrantLock,因为涉及到多张表的查看及更新,也用到了事务,因为锁和事务,遇到了一些问题

2、解决

先说解决方案,遇到的问题放在第三点,想看的可以看看
首先参考这篇章
https://blog.csdn.net/zzhongcy/article/details/103583008
写了一个切面,但要注意的是必须要加@order注解,否则锁不住。
另外要把切面的catch去掉,将异常抛出,否则事务会失效

@Component
@Aspect
@Order(1)
public class LockAspect {

    private  final Lock lock = new ReentrantLock();

    @Pointcut("@annotation(Servicelock)")
    public void lockAspect() {}

    @Around("lockAspect()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        lock.lock();
        Object obj;
        //catch会导致事务失效,所以抛出异常
        try {
            obj = joinPoint.proceed();
        }
        finally {
            lock.unlock();
        }
        return obj;
    }
}

3、思路及解决步骤

3.1、首先我想的是直接写一个工具类,让其他人调用生成编号的

  public String getNumber(Long reportId, String category) {
        NumberControl numberControl = numberControlManage.selectByReportIdAndNumberCategory(reportId, category);
        if (numberControl != null) {
            //人工编号返回null
            if (ConstantPool.ONE.toString().equals(numberControl.getNumberType())) {
                return null;
            }

            Integer digit = numberControl.getDigit();
            String predix = generatePrefix(numberControl);

           
            lock.lock();
            try {
                //去生成编号中查询一下
                GenerateNumber generateNumber = generateNumberManage.getByPrefixAndCategory(predix, category, digit);
                //说明没有
                if (generateNumber == null) {
                    generateNumber = new GenerateNumber();
                    generateNumber.setPrefix(predix);
                    generateNumber.setNumberCategory(category);
                    generateNumber.setDigit(digit);
                    generateNumberManage.save(generateNumber);
                    return predix + formatNumber(digit, 1);
                } else {
                    Long number = generateNumber.getNumber() + 1;
                    generateNumber.setNumber(number);
                    generateNumberManage.updateById(generateNumber);
                    return predix + formatNumber(digit, number.intValue());
                }
            } catch (Exception e) {
                log.error(e.getMessage(), e);
            } finally {
                lock.unlock();
            }

        }
        return null;
    }

这里直接使用ReentrantLock锁住,但是当上层方法加上事务的时候,会导致锁失效。
简单来说就是:事务还未提交的时候,锁已经释放了

   @Transactional(rollbackFor = Exception.class)
    public R<Boolean> copy(EntrustCopyDto dto) {
        EntrustSamples byId = entrustSamplesManage.getById(dto.getId());
        //将id置为空
        byId.setId(null);

        String number;
        if (ConstantPool.YES.toString().equals(dto.getPreEntrust())) {
        //这里走完锁就会被释放掉,而事务还未被提交
            number = numberControlService.getNumber(byId.getCheckProjectId(), NumberCategoryEnum.PREENTRUST.getCode());
        } else {
            number = numberControlService.getNumber(byId.getCheckProjectId(), NumberCategoryEnum.ENTRUST.getCode());
        }
        byId.setCommissionNumber(number);
        return R.ok(entrustSamplesManage.save(byId));
    }

3.2、发现上面这样写不行,改成切面方式

https://blog.csdn.net/zzhongcy/article/details/103583008
当然也有其他方式,可参考
https://blog.csdn.net/small_love/article/details/127263276
按理说,这样应该可以了,但是发现还是锁不住

3.3、添加@order

因为看文章提到了@order,抱着死马当活马医的心态加上去了,结果竟然好了。不信邪,又去掉@order压测,加上@order压测尝试了好几遍,发现加上去之后确实可以。
于是之后就开始查找原因,之前看文章说@Transactional的默认优先级就是Integer.MAX_VALUE,数字越大优先级越低,想着默认的怎么也不至于比它优先级还低吧。。。。
结果还真是一样低。
首先进去@order注解,发现是通过这个类来进行比较优先级别的
在这里插入图片描述
然后进去该类,翻译
在这里插入图片描述
大体就是这样了,折腾了很久。。。。

相关推荐

  1. MySQL事务04

    2024-07-12 02:56:06       44 阅读
  2. Spring 事务事务传播机制

    2024-07-12 02:56:06       40 阅读
  3. spring 事务方式事务传播

    2024-07-12 02:56:06       20 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-12 02:56:06       67 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-12 02:56:06       72 阅读
  3. 在Django里面运行非项目文件

    2024-07-12 02:56:06       58 阅读
  4. Python语言-面向对象

    2024-07-12 02:56:06       69 阅读

热门阅读

  1. Linux——测网速例子,在网站查看生成的图片

    2024-07-12 02:56:06       28 阅读
  2. 华为od-C卷200分题目6 - 5G 网络建设

    2024-07-12 02:56:06       23 阅读
  3. python(餐厅点餐系统)

    2024-07-12 02:56:06       24 阅读
  4. 【数理统计】2-随机变量及其概率分布

    2024-07-12 02:56:06       21 阅读
  5. python在区块链领域中的应用

    2024-07-12 02:56:06       17 阅读
  6. AI全新应用设想:畅想智能体和应用软件的结合

    2024-07-12 02:56:06       19 阅读
  7. Android Bitmap

    2024-07-12 02:56:06       21 阅读
  8. C++list的模拟实现

    2024-07-12 02:56:06       25 阅读
  9. Zookeeper-数据结构

    2024-07-12 02:56:06       24 阅读
  10. c++ learn five five day

    2024-07-12 02:56:06       23 阅读
  11. 自定义激活函数:Mojo模型的动态选择之道

    2024-07-12 02:56:06       22 阅读