生成编号的函数返回了重复的值(手动commit验证时,发MySQL表中出现了两条编号数据。commit后又消失了)

wangwangbinbin 2016-09-08 02:51:46
出现了如下的问题,希望大家能帮忙分析下。
1.为什么有编号重复
2.为什么MySQL的更新过程中出现了两条记录。

※问题
数据库中,有个生成编号的函数。实际运用中,返回了重复的编号。
>编号的结构是【地区+日期+5位长的数字<从1开始顺序号码>】
>例子:ab2016090800001
后来经过把MySQL调成手动commit,同时开两个终端模拟了这个问题
Step1->终端1:生成编号,不commit

Step2->终端2:生成编号时,由于表被锁,处理卡住

Step3->终端1:commit

Step4->终端2:编号生成,保存顺序号码的表里出现了两条数据

Step5->终端2:commit,保存顺序号码的表中的两条数据又变成一条
生成的编号和现有的编号重复

上面的描述可能不太清楚,下面我会附上实际执行时的截图和数据库结构。

※实际执行结果






※数据库结构
1.表
1-1:注册数据表->applies,apply_no:编号,district_cd:地区
CREATE TABLE `applies` (
`apply_id` varchar(100) NOT NULL DEFAULT '',
`apply_no` varchar(100) NOT NULL DEFAULT '',
`district_cd` varchar(100) DEFAULT NULL,
`created` datetime DEFAULT NULL,
PRIMARY KEY (`apply_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

1-2:编号顺序表->保存各个地区每天的当前的顺序号码,district_cd:地区,current_value:顺序号码,apply_date:日期
CREATE TABLE `sequence` (
`district_cd` varchar(3) NOT NULL DEFAULT '',
`current_value` int(11) NOT NULL DEFAULT '0',
`apply_date` date NOT NULL DEFAULT '0000-00-00',
PRIMARY KEY (`district_cd`,`current_value`,`apply_date`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

2.函数
2-1:currval->以地区为参数取得当前的顺序号码
DELIMITER ;;
CREATE DEFINER=`usr`@`%` FUNCTION `currval`(d VARCHAR(3)) RETURNS int(11)
DETERMINISTIC
BEGIN
DECLARE value INTEGER;
DECLARE needInitSequence INTEGER;
DECLARE today DATE;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET needInitSequence = 1;

SET value = 0;
SET today = current_date();

SELECT `current_value` INTO value
FROM `sequence`
WHERE `district_cd` = d AND `apply_date` = today limit 1;

IF needInitSequence = 1 THEN
INSERT INTO `sequence` (`district_cd`, `current_value`, `apply_date`) VALUES (d, value, today);
END IF;

RETURN value;
END
;;
DELIMITER ;

2-2:nextval->以地区为参数生成编号
DELIMITER ;;
CREATE DEFINER=`usr`@`%` FUNCTION `nextval`(d VARCHAR(3)) RETURNS varchar(16) CHARSET utf8
DETERMINISTIC
BEGIN
DECLARE value INTEGER;
SET value = currval(d);

UPDATE `sequence`
SET `current_value` = `current_value` + 1
WHERE `district_cd` = d AND `apply_date` = current_date();

RETURN concat(d, date_format(now(), '%Y%m%d'), LPAD(currval(d), 5, '0'));
END
;;
DELIMITER ;

3.触发器
applies表,如果插入的编号大于18就调用nextval重新生成编号。
※此处是实际业务的一个处理。
DELIMITER ;;
CREATE TRIGGER `convert_long_no` BEFORE INSERT ON `applies` FOR EACH ROW BEGIN
IF ((SELECT LENGTH(NEW.apply_no)) >= 18) THEN
SET NEW.apply_no = (SELECT nextval(NEW.district_cd));
END IF;
END
;;
DELIMITER ;


如果有其他信息要提供请回复我。

...全文
314 1 打赏 收藏 转发到动态 举报
写回复
用AI写文章
1 条回复
切换为时间正序
请发表友善的回复…
发表回复
zjcxc 2016-09-09
  • 打赏
  • 举报
回复
加个事务 STATR TRANSACTION; SET value = currval(d);       UPDATE `sequence`         SET `current_value` = `current_value` + 1         WHERE `district_cd` = d AND `apply_date` = current_date(); COMMIT;

56,679

社区成员

发帖
与我相关
我的任务
社区描述
MySQL相关内容讨论专区
社区管理员
  • MySQL
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧