采用mysql存储过程生成唯一流水号功能,支持并发。
项目中需要生产出库单的流水号,之前用了很多方法都无法解决并发时流水号重复的问题。
直到看见csdn上《关于生成并发唯一性流水号的解决方案》这篇文章,茅塞顿开,作者写的太好了。
尤其是使用update来进行锁定表内容,大大降低了代码难度。因为项目采用的是mysql数据库,因此采用mysql的存储过程重新写了一边。
1 创建数据库: sys_sno
CREATE TABLE `sys_sno` (
`sCode` varchar(50) DEFAULT NULL,
`sName` varchar(100) DEFAULT NULL,
`sQz` varchar(50) DEFAULT NULL,
`sValue` varchar(80) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
2
DELIMITER $$
USE `hrpdb`$$
DROP PROCEDURE IF EXISTS `GetSerialNo`$$
CREATE DEFINER=`root`@`localhost` PROCEDURE `GetSerialNo`(IN tsCode VARCHAR(50),OUT result VARCHAR(200) )
BEGIN
DECLARE tsValue VARCHAR(50);
DECLARE tdToday VARCHAR(20);
DECLARE nowdate VARCHAR(20);
DECLARE tsQZ VARCHAR(50);
DECLARE t_error INTEGER DEFAULT 0;
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET t_error=1;
START TRANSACTION;
UPDATE sys_sno SET sValue=sValue WHERE sCode=tsCode;
SELECT sValue INTO tsValue FROM sys_sno WHERE sCode=tsCode;
SELECT sQz INTO tsQZ FROM sys_sno WHERE sCode=tsCode ;
-- 因子表中没有记录,插入初始值
IF tsValue IS NULL THEN
SELECT CONCAT(DATE_FORMAT(NOW(),'%y%m'),'0000001') INTO tsValue;
UPDATE sys_sno SET sValue=tsValue WHERE sCode=tsCode ;
SELECT CONCAT(tsQZ,tsValue) INTO result;
ELSE
SELECT SUBSTRING(tsValue,1,4) INTO tdToday;
SELECT CONVERT(DATE_FORMAT(NOW(),'%y%m'),SIGNED) INTO nowdate;
IF tdToday = nowdate THEN
SET tsValue=CONVERT(tsValue,SIGNED) + 1;
ELSE
SELECT CONCAT(DATE_FORMAT(NOW(),'%y%m') ,'0000001') INTO tsValue ;
END IF;
UPDATE sys_sno SET sValue =tsValue WHERE sCode=tsCode;
SELECT CONCAT(tsQZ,tsValue) INTO result;
END IF;
IF t_error =1 THEN
ROLLBACK;
SET result = 'Error';
ELSE
COMMIT;
END IF;
SELECT result ;
END$$
DELIMITER ;
DATE_FORMAT(NOW(),'%y%m')
特别注意:
2016年11月14日时 '1611140000001'
SUBSTRING(tsValue,1,6) 后的值与 DATE_FORMAT(NOW(),'%y%m') 相等
SUBSTRING(tsValue,1,4) 后的值与 DATE_FORMAT(NOW(),'%y') 不相等!!
原因是1614强制赋值给datetime类型时 其不是一个有效的datetime值 因此 与 DATE_FORMAT(NOW(),'%y') 不同。
所以项目中使用
DECLARE tdToday VARCHAR(20);
DECLARE nowdate VARCHAR(20); 来作为中转解决问题。