我们在做订单模块的时候通常将订单定义为String类型的,因为订单号是有一系列的编码规则的。
首先我们假定订单有16位码。我们将这16位码分成3部分进行一个对应
这里的分库分表后续会单独写。这里定义2位00
新建一个StringBuilder用来存放字符串
StringBuilder stringBuilder = new StringBuilder();
时间日期的8位模拟实现
//年月日 8位
LocalDateTime now = LocalDateTime.now();
String nowDate = now.format(DateTimeFormatter.ISO_DATE).replace("-","");
stringBuilder.append(nowDate);
自增长的 6 位实现
自增长的 6 位需要借助持久化来实现,首先需要建立一个序列增长的表,这个表的作用就是来控制我们表的6位增长。建表信息如下:
CREATE TABLE `sequence_info` (
`name` varchar(255) NOT NULL DEFAULT '0',
`current_value` int(11) NOT NULL DEFAULT '0',
`step` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='订单编号增长序列信息';
各个字段的解释如下
建立字段增长表
有了表之后我们就有了一个思路:首先我们要给数据库表中一个初始值,让current_value从0开始增加,step为1。
insert into sequence_info(name,current_value,step) values("order_info","0","1");
接下来我们通过业务逻辑实现
我们先查询到order_info的所在信息,因为我们的自增长id序列可能要设置多个属性,比如商品id也可以通过这种方进行设置。所以我们设置了name这个字段保证我们在用order_info的时候来查找到。这样就可以获取到当前的增长序列
int sequence = 0;
//获取Sequence
SequenceDO sequenceDO = sequenceDOMapper.getSequenceByName("order_info");
sequence = sequenceDO.getCurrentValue();
注意我们在查找的时候应该保证给数据库加锁,下面是sequenceDOMapper.getSequenceByName方法的sql语句
<select id="getSequenceByName" parameterType="java.lang.String" resultMap="BaseResultMap">
select
from sequence_info
where name = #{name,jdbcType=INTEGER} for update
</select>
接着对current_value + step 设置下次的增长序列
sequenceDO.setCurrentValue(sequenceDO.getCurrentValue()+sequenceDO.getStep());
sequenceDOMapper.updateByPrimaryKey(sequenceDO);
最后对不足6位的数字进行一个0的拼接
String sequenceStr = String.valueOf(sequence);
for (int i = 0; i <6 - sequenceStr.length(); i++) {
stringBuilder.append(0);
}
stringBuilder.append(sequenceStr);
如果说我们的表增长超过了6位,我们就让它的下一次继续从0开始循环。
Integer nextSequence = sequenceDO.getCurrentValue()+sequenceDO.getStep() ;
if (nextSequence >= 1000000) {
sequenceDO.setCurrentValue(0);
sequenceDOMapper.updateByPrimaryKey(sequenceDO);
}