平时工作中我们经常会生成各种单号,大部分的单号都是日期加上自增长的序列如:VC20181115001,VC201811151525001,常用格式: 字母 + yyyyMMdd + 001,字母 + yyyyMMddHHmmss + 001等等。
我们可以使用mysql解决这个问题,使用存储过程调用,适合普通单号生成,不适合高并发的单号生成。
1.我们新建一张序列表 sys_sequence
CREATE TABLE `sys_sequence` (
`name` varchar(32) NOT NULL,
`value` int(10) DEFAULT NULL,
`step` smallint(5) DEFAULT NULL,
`start` int(10) DEFAULT NULL,
PRIMARY KEY (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
name 字段为我们设置的字母标识,value 字段为当前的序列号,step为每次增长的数字大小,start为起始数字
2.我们新建一个存储过程来调用生成序列,也可以用代码
CREATE PROCEDURE `generateSeq`(
IN m VARCHAR(100),OUT n INTEGER
)
BEGIN
DECLARE t_error INTEGER DEFAULT 0;
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET t_error=1;
START TRANSACTION;
SET @v:= (SELECT EXISTS (SELECT `value` FROM `sys_sequence` WHERE `name`=m));
SET @m=0;
IF(@v=0) THEN
INSERT INTO `sys_sequence`(`name`,`value`,`step`,`start`) VALUE(m,(SELECT @m:=1),1,1);
ELSE
UPDATE `sys_sequence` SET `value`=@m:=`value`+1 WHERE `name`=m;
END IF;
SET n=@m;
IF t_error =1 THEN
ROLLBACK;
SET n = -1;
ELSE
COMMIT;
END IF;
SELECT n ;
END
存储过程一个入参 name,一个出参n
首先根据传入的参数name查询出当前的序列值value,做个判断如果这个value值等于0则表示是第一次生成序列号,则默认即将生成的序列号为1,自增长为1,如果value值不等0则表示不是第一次生成序列号,则更新当前获取的序列号value值加1,最后在返回生成的序列号。
3.代码调用
我们可以用mybatis代码生成器生成表 sys_sequence 的代码,然后放进项目里,这里步骤省略。
SequenceService代码:
@Service
public class SequenceService {
@Autowired
private SequenceExMapper sequenceExMapper
//使用存储过程事物控制
@Transactional(readOnly = false, propagation = Propagation.NOT_SUPPORTED)
public int getSeq(String name){
Sequence sq = new Sequence();
sq.setName(name);
int value = sequenceExMapper.getSeq(sq);
return value;
}
}
SequenceExMapper代码:
@Repository
public interface SequenceExMapper {
int getSeq(Sequence sequence);
}
SequenceExMapper.xml 代码:
<select id="getSeq" statementType="CALLABLE" resultType="INTEGER">
{ CALL generateSeq(
#{name,jdbcType=VARCHAR,mode=IN},
#{value,jdbcType=INTEGER,mode=OUT})
}
</select >
Sequence 对象代码:
public class Sequence implements Serializable{
private static final long serialVersionUID = 1L;
private java.lang.String name;//
private java.lang.Integer value;//
private Short step;//
private java.lang.Integer start;//
// 省略get和set方法
}
我们在需要生成单号的地方调用 SequenceService的getSeq方法即可,注意这个方法返回的只是一个当前的序列号数字如5,如果想要005这样的就需要我们再次拼接一下。
新建一个 CertificationService 代码:
@Service
public class CertificationService {
private static Logger logger = LoggerFactory.getLogger(CertificationService.class);
@Autowired
private SequenceService sequenceService;
/**
* 获取编码,格式如 VC20181115001
* @return
*/
public String getSeqDateNo() {
int seqNo = sequenceService.getSeq("VC");
String suffixCode = String.format("%03d", seqNo);
String currentDate = DateUtil.getDateStringCompact(new Date());
String certificationNo = "VC" + currentDate + suffixCode;
return certificationNo;
}
/**
* 获取编码,格式如 VC201811151525001
* @return
*/
public String getSeqDateTimeNo() {
int seqNo = sequenceService.getSeq("VC");
String suffixCode = String.format("%03d", seqNo);
String currentDate = DateUtil.getDateTimeString4(new Date());
String certificationNo = "VC" + currentDate + suffixCode;
return certificationNo;
}
}
DateUtil的代码点击查看