我们的网络系统中有一个MySQL函数来生成代码。代码的结构是
district_cd(length:2) + date(length:8) + sequence no(length:5,start at 1).<like : ab2016090800001>
序列号保存在表格中,并在生成新代码时更新(+1)。
但有时候它会返回两个相同的代码,让我们陷入困境。以下是复制此问题的捕获,我将在此之后附加DDL。
步骤1.Client1-&gt;更改为手动提交然后生成代码,但不提交。
SET autocommit = 0;
select * from applies;
select * from sequence where apply_date = "2016-09-08";
select nextval("ab");
insert into applies (apply_id,apply_no,created,district_cd) values (2,"ab2016090800002","ab",now());
select * from sequence where apply_date = "2016-09-08";
Step2.Client2-&gt;更改为手动提交然后生成代码,卡在Client1锁定
SET autocommit = 0;
select * from applies;
select * from sequence where apply_date = "2016-09-08";
insert into applies (apply_id,apply_no,created,district_cd) values (3,"ab20160908123456780","ab",now());
Step3.Client1-&GT;提交;
commit;
select * from sequence where apply_date = "2016-09-08";
生成了Step4.Client2-&gt;代码,并且在序列表中出现了两条记录
select * from sequence where apply_date = "2016-09-08";
Step5.Client2-&gt; commit;删除了序列表中出现的两条记录之一。生成的代码是重复的。
commit;
select * from sequence where apply_date = "2016-09-08";
select * from applies;
※DDL
表:适用(apply_no:保存代码)
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;
表:序列(current_value:保存当前序列值)
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;
功能:currval-&gt;通过district_cd获取当前序列值
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 ;
功能:nextval-&gt;按区域生成代码
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 ;
应用的触发器 - &gt;业务逻辑,如果apply_no的长度大于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 ;
我的问题:
为什么函数:nextval返回两个相同的代码?
为什么在更新记录时会出现两条记录。