直接上代码!!
CREATE DEFINER=`root`@`localhost` PROCEDURE `getOrderSerialNo`(
# 前缀
in orderPrefix varchar(64),
# 返回结果
out result int
)
BEGIN
# 当前流水号
declare curOrderNo int;
# 默认值为0
declare errorResult int default 0;
# 生成失败返回
declare continue handler for sqlexception set errorResult = -1;
#开启事务
start transaction;
select cur_order_no into curOrderNo from t_order_serial_no where order_prefix = orderPrefix;
# 如果该前缀是第一次生成 则插入1
if curOrderNo is null then
insert into t_order_serial_no(order_prefix, cur_order_no) values (orderPrefix, 1);
select 1 into result;
else
# 否则递增
update t_order_serial_no set cur_order_no = cur_order_no + 1 where order_prefix = orderPrefix;
select cur_order_no into result from t_order_serial_no where order_prefix = orderPrefix;
end if;
if errorResult = -1 then
rollback;
set result = -1;
else
commit;
end if;
select result;
END
CREATE TABLE `t_order_serial_no` (
`id` int(10) NOT NULL AUTO_INCREMENT COMMENT '主键',
`order_prefix` varchar(64) NOT NULL COMMENT '订单号前缀',
`cur_order_no` int(10) NOT NULL COMMENT '当前流水号数值',
PRIMARY KEY (`id`),
UNIQUE KEY `order_prefix_unique_idx` (`order_prefix`) USING BTREE COMMENT '唯一键索引'
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;
@Service
public class OrderService {
@Resource
private OrderDAO orderDAO;
/**
* 订单流水号生成规则:order+年月日+5位不重复递增流水号(00001开始)
* @return
*/
public String getOrderSerialNumber() {
String result;
// 订单流水号前缀
String orderPreFix = "ORDER" + LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")).replaceAll("-", "");
// 请求参数
Map<String, Object> requestMap = new HashMap<>();
// 输入参数
requestMap.put("orderPrefix", orderPreFix);
// 输出参数
requestMap.put("result", 0);
Integer orderSerialNumber = orderDAO.getOrderSerialNumber(requestMap);
if (Objects.isNull(orderSerialNumber) || -1 == orderSerialNumber) {
throw new RuntimeException("生成失败!");
}
String serialNumberStr = getSerialNumber(orderSerialNumber, 5);
result = orderPreFix + serialNumberStr;
return result;
}
/**
* 流水号位数
* @param number 流水号数值
* @param counts 位数
* @return
*/
public static String getSerialNumber(int number, int counts) {
String result = "";
for(int i = (number+"").length() ; i < counts; i++){
result += "0";
}
result += number;
return result;
}
}
/**
* 获取订单流水号数值
* @param requestMap
* @return
*/
Integer getOrderSerialNumber(Map<String, Object> requestMap);
<select id="getOrderSerialNumber" parameterType="java.util.Map" statementType="CALLABLE" resultType="java.lang.Integer">
{
CALL getOrderSerialNo(
#{orderPrefix, mode=IN,jdbcType=VARCHAR},
#{result, mode=OUT,jdbcType=INTEGER}
)
}
</select>
@Autowired
private OrderService orderService;
@RequestMapping("/getSerialNum")
public String getSerialNum() {
return orderService.getOrderSerialNumber();
}
调用该接口进行完整订单流水号生成:
以上示例演示的流水号生成规则是ORDER+年月日+五位数字(递增,不够0填充)
注意: 在高并发情况下,只有数据库事务的隔离级别设置为REPEATABLE-READ及以上才可行。