生成規則
我們在做訂單模塊的時候通常將訂單定義爲String類型的,因爲訂單號是有一系列的編碼規則的。
首先我們假定訂單有16位碼。我們將這16位碼分成3部分進行一個對應
- 前8位,時間日期如 :20190603
- 中間 6 位 ,自增長序列從000001到999999保持增長
- 後 2 位,分庫分表位
這裏的分庫分表後續會單獨寫。這裏定義2位00
訂單Id生成模擬
新建一個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='訂單編號增長序列信息';
各個字段的解釋如下
- name : 標誌自增長的信息名字 current_value : 我們要獲取的信息值
- step :信息增長值
建立字段增長表
有了表之後我們就有了一個思路:首先我們要給數據庫表中一個初始值,讓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);
}