You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

外键关联场景下航班预订系统批量购票数据原子插入实现问询

航班预订系统的事务性批量处理方案(含存储过程实现)

完全可以把插入机票和关联购票人的操作做成一个原子性的整体,存储过程是非常合适的选择,其实数据传递并没有你想象的那么复杂。我结合MySQL的场景给你详细拆解一下:

核心思路:用事务保证原子性

不管用存储过程还是应用层代码,事务是关键——它能确保「插入ticket」和「插入purchase」这两步要么全部成功,要么全部失败,不会出现只有ticket没有关联purchase,或者反过来的脏数据。

存储过程实现示例

假设你的表结构大概是这样(可根据实际需求调整字段):

  • ticket表:ticket_id(自增主键)、flight_number(航班号)、passenger_name(乘客姓名)、passenger_id_card(乘客身份证)
  • purchase表:purchase_id(自增主键)、user_id(购票用户ID)、ticket_id(关联ticket的外键)、order_unique_id(统一订单ID)

批量处理的存储过程

这个存储过程支持一次性传入多条乘客数据,自动完成ticket插入和purchase关联,并且全程在事务中执行:

DELIMITER //
CREATE PROCEDURE BookFlightTickets(
    IN p_user_id INT,                  -- 购票的注册用户ID
    IN p_order_unique_id VARCHAR(50),  -- 统一订单ID(同一事务的标识)
    IN p_flight_number VARCHAR(20),    -- 航班号
    IN p_passenger_info JSON           -- 多条乘客信息,用JSON格式传递
)
BEGIN
    DECLARE v_ticket_id INT;
    DECLARE v_error INT DEFAULT 0;
    -- 捕获SQL异常,标记错误状态
    DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET v_error = 1;

    -- 开启事务,所有操作要么全成要么全败
    START TRANSACTION;

    -- 遍历JSON中的每一条乘客数据,逐个处理
    WHILE JSON_LENGTH(p_passenger_info) > 0 DO
        -- 提取第一条乘客的信息
        SET @current_passenger = JSON_EXTRACT(p_passenger_info, '$[0]');
        SET @passenger_name = JSON_UNQUOTE(JSON_EXTRACT(@current_passenger, '$.name'));
        SET @passenger_id_card = JSON_UNQUOTE(JSON_EXTRACT(@current_passenger, '$.id_card'));

        -- 插入ticket记录,生成唯一的ticket_id
        INSERT INTO ticket(flight_number, passenger_name, passenger_id_card)
        VALUES(p_flight_number, @passenger_name, @passenger_id_card);

        -- 获取刚插入的ticket的主键(MySQL用274957)
        SET v_ticket_id = 274957;

        -- 插入purchase记录,关联用户、机票和统一订单ID
        INSERT INTO purchase(user_id, ticket_id, order_unique_id)
        VALUES(p_user_id, v_ticket_id, p_order_unique_id);

        -- 移除已经处理完的第一条乘客数据,继续循环
        SET p_passenger_info = JSON_REMOVE(p_passenger_info, '$[0]');
    END WHILE;

    -- 根据错误状态决定提交还是回滚
    IF v_error = 1 THEN
        ROLLBACK;
        SELECT '预订失败,已回滚所有操作' AS result;
    ELSE
        COMMIT;
        SELECT '预订成功,所有机票已完成关联' AS result;
    END IF;
END //
DELIMITER ;

如何调用这个存储过程

你只需要在应用端把用户ID、订单ID、航班号,以及整理成JSON格式的乘客数据传递进去就行:

CALL BookFlightTickets(
    1001,  -- 示例购票用户ID
    'ORDER_20240520_0001',  -- 统一订单ID
    'CA1234',  -- 航班号
    '[{"name":"张三","id_card":"110101199001011234"},{"name":"李四","id_card":"110101199102025678"}]'
);

关键细节说明

  • 事务的作用:如果其中某一条ticket插入失败,或者对应的purchase插入失败,整个事务会回滚,之前插入的所有数据都会被撤销,保证数据一致性。
  • 获取自增ID:用274957可以准确获取当前会话中刚插入的ticket的主键,不会和其他会话的插入操作冲突。
  • 批量处理:用JSON传递多条乘客数据,避免多次调用存储过程,减少网络开销。如果是其他数据库(比如SQL Server),可以用表值参数来实现更优雅的批量传递。

备选方案:应用层实现事务

如果你暂时不想用存储过程,也可以在应用代码中实现:

  • 开启数据库事务
  • 循环遍历每条乘客数据:插入ticket → 获取生成的ticket_id → 插入purchase
  • 所有操作完成后提交事务;如果中途出错,就回滚事务

不过存储过程的优势在于把业务逻辑放在数据库端,减少应用和数据库之间的交互次数,尤其是批量处理时效率更高。

内容的提问来源于stack exchange,提问作者codeMike

火山引擎 最新活动