Java+Mysql存储过程生成订单序列号

Mysql存储过程生成唯一订单号

直接上代码!!

1.创建存储过程

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

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 {

    @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;
    }
}

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 层

    @Autowired
    private OrderService orderService;

    @RequestMapping("/getSerialNum")
    public String getSerialNum() {
        return orderService.getOrderSerialNumber();
    }

调用该接口进行完整订单流水号生成:
在这里插入图片描述

4.结果

以上示例演示的流水号生成规则是ORDER+年月日+五位数字(递增,不够0填充)在这里插入图片描述
注意: 在高并发情况下,只有数据库事务的隔离级别设置为REPEATABLE-READ及以上才可行。

  • 11
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
如果你不想使用Redis来实现序列号生成,你可以考虑使用数据库来存储和管理序列号。 以下是一个基于数据库的实现示例,假设你使用的是MySQL数据库: 1. 创建一个名为`serial_numbers`的表,用于存储序列号和日期信息: ```sql CREATE TABLE serial_numbers ( id INT AUTO_INCREMENT PRIMARY KEY, date DATE, counter INT ); ``` 2. 在每个服务中,使用数据库连接库(如JDBC)连接到数据库。 3. 在生成序列号的方法中,首先查询数据库表中当天的记录。如果不存在,则插入一条新的记录;如果存在,则更新计数器值。 ```java import java.sql.*; public class SerialNumberGenerator { private static final String DB_URL = "jdbc:mysql://localhost:3306/your_database_name"; private static final String DB_USERNAME = "your_username"; private static final String DB_PASSWORD = "your_password"; private static final String DATE_FORMAT = "yyyy"; private static final String SERIAL_FORMAT = "SA%s%03d"; public static String generateSerialNumber() { try (Connection connection = DriverManager.getConnection(DB_URL, DB_USERNAME, DB_PASSWORD); Statement statement = connection.createStatement()) { Date today = new Date(System.currentTimeMillis()); String query = "SELECT * FROM serial_numbers WHERE date = '" + today + "'"; ResultSet resultSet = statement.executeQuery(query); if (resultSet.next()) { int counter = resultSet.getInt("counter") + 1; String serialNumber = String.format(SERIAL_FORMAT, today.toLocalDate().format(DateTimeFormatter.ofPattern(DATE_FORMAT)), counter); String updateQuery = "UPDATE serial_numbers SET counter = " + counter + " WHERE date = '" + today + "'"; statement.executeUpdate(updateQuery); return serialNumber; } else { String insertQuery = "INSERT INTO serial_numbers (date, counter) VALUES ('" + today + "', 1)"; statement.executeUpdate(insertQuery); return String.format(SERIAL_FORMAT, today.toLocalDate().format(DateTimeFormatter.ofPattern(DATE_FORMAT)), 1); } } catch (SQLException e) { e.printStackTrace(); } return null; } public static void main(String[] args) { System.out.println(generateSerialNumber()); System.out.println(generateSerialNumber()); System.out.println(generateSerialNumber()); } } ``` 这个示例代码中,我们首先建立了与数据库的连接,并根据当前日期查询数据库表。如果存在当天的记录,则更新计数器并返回新的序列号。如果不存在当天的记录,则插入一条新的记录并返回序列号。 需要注意的是,这个示例代码中使用了简单的SQL语句拼接,这可能存在SQL注入的安全风险。在实际生产环境中,建议使用参数化查询或ORM框架来执行数据库操作,以避免安全问题。 另外,需要确保数据库连接是线程安全的,以便在多个服务上并发生成序列号时能够正常工作。你可以使用连接池来管理数据库连接,以提高性能和并发能力。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值