设计自增流水规则表

  • 创建存储流水号状态的表,包含规则的信息
sql
  • 01
  • 02
  • 03
  • 04
  • 05
  • 06
  • 07
  • 08
  • 09
  • 10
  • 11
  • 12
CREATE TABLE `invoice_sequence` ( `rule_code` varchar(20) NOT NULL COMMENT '规则编码', `prefix` varchar(20) NOT NULL COMMENT '流水号前缀', `date_format` varchar(20) NOT NULL COMMENT '日期格式', `number_length` int DEFAULT NULL COMMENT '流水号长度', `current_date_str` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '当前日期', `current_number` int DEFAULT NULL COMMENT '流水号位置', `remark` varchar(255) DEFAULT NULL COMMENT '备注信息', `create_time` datetime DEFAULT NULL COMMENT '创建时间', `create_by` varchar(255) DEFAULT NULL COMMENT '创建人', PRIMARY KEY (`rule_code`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='通用自定义自增规则流水号表';
  • 初始化数据
sql
  • 01
  • 02
INSERT INTO `invoice_sequence` (`rule_code`, `prefix`, `date_format`, `number_length`, `current_date`, `current_number`, `remark`) VALUES ('FLRK', 'FLRK', '%Y%m', 4, '202201', 0, '废料入库单据流水号');
  • 重点来了 获取流水id函数(过程)
sql
  • 01
  • 02
  • 03
  • 04
  • 05
  • 06
  • 07
  • 08
  • 09
  • 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
create definer = root@`%` procedure GenerateNewInvoiceNumber(IN p_rule_code varchar(20)) BEGIN -- 定义接值的参数 DECLARE v_number_length INT; #流水长度 DECLARE v_prefix VARCHAR(20); #流水前缀 DECLARE v_date_format VARCHAR(20); #时间格式化方式 DECLARE v_current_date VARCHAR(20); #上次生成流水的格式化时间 DECLARE v_current_number INT; #上次生成流水的值 DECLARE v_count INT; #是否存在当前流水规则的CODE -- 设置事务超时时间为 10 秒 SET innodb_lock_wait_timeout = 10; START TRANSACTION; -- 预先获取规则信息 -- 获取流水长度,流水前缀,时间格式化字符串,流水最新的时间 SELECT `number_length`, `prefix`, `date_format`, `current_date_str`, `current_number`, count(1) INTO v_number_length, v_prefix, v_date_format,v_current_date ,v_current_number,v_count FROM `invoice_sequence` WHERE `rule_code` = p_rule_code FOR UPDATE; IF v_count = 0 THEN #如果CODE未被查询出来 SIGNAL SQLSTATE '45001' SET MESSAGE_TEXT = "当前单据CODE不存在配置表中"; END IF; -- 生成新流水号 SET @newNumber = 0; SET @tempDataStr = DATE_FORMAT(NOW(), v_date_format); -- 判断当前日期是否与存储的日期一致 IF v_current_date = @tempDataStr THEN SET @newNumber = v_current_number + 1; -- 更新表中的状态 UPDATE `invoice_sequence` SET `current_number` = @newNumber WHERE `rule_code` = p_rule_code; ELSE -- 获取当前流水号 SET @newNumber = 1; -- 更新表中的状态 UPDATE `invoice_sequence` SET `current_number` = @newNumber, `current_date_str` = @tempDataStr WHERE `rule_code` = p_rule_code; END IF; -- 格式化新流水号为指定长度 SET @formattedNewNumber = LPAD(@newNumber, v_number_length, '0'); -- 提交事务 COMMIT; -- 恢复默认事务超时时间 SET innodb_lock_wait_timeout = 50; -- 最终生成的流水号 SELECT CONCAT(v_prefix, DATE_FORMAT(NOW(), v_date_format), @formattedNewNumber) AS `new_invoice_number`; END;
  • 测试获取流水号

  • 并发场景测试
    开启10个线程并发生成流水id

    顺利生成流水id