Mysql存储过程生成唯一订单号
直接上代码!!
1.创建存储过程
CREATE DEFINER=`root`@`localhost` PROCEDURE `getOrderSerialNo`(# 前缀in orderPrefix varchar(64), # 返回结果out result int)
BEGIN# 当前流水号declare curOrderNo int;# 默认值为0declare 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;# 如果该前缀是第一次生成 则插入1if curOrderNo is null theninsert 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
2.创建数据表
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;
3.代码
3.1 service层
@Service
public class OrderService {@Resourceprivate 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;}
}
3.2 OrderDAO
/*** 获取订单流水号数值* @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>
3.3 controller 层
@Autowiredprivate OrderService orderService;@RequestMapping("/getSerialNum")public String getSerialNum() {return orderService.getOrderSerialNumber();}
调用该接口进行完整订单流水号生成:
4.结果
以上示例演示的流水号生成规则是ORDER+年月日+五位数字(递增,不够0填充)
注意: 在高并发情况下,只有数据库事务的隔离级别设置为REPEATABLE-READ及以上才可行。