跳转至
🧪 本课内容基本定稿,校对中——发现错漏欢迎评论区指出。

第14课:BAPI 调用 —— SAP 标准业务接口

45分钟 | 阶段:高级篇 | 建议边读边做

前置依赖

  • 第9课:CALL FUNCTION 与 RFC 概念(BAPI 的谜底);
  • 第5课:COMMIT WORK 与 LUW。

问题引入

程序要"自动创建一条航班预订"——座位检查、价格计算、库存锁定这套逻辑自己写?SAP 早已封装好,以 BAPI(Business Application Programming Interface)对外开放:它是 RFC-enabled 的 FM + 严格的接口规范(RET2 返回表、独立事务控制)。掌握 BAPI,你就能安全地驱动 SAP 的全部标准业务,而不是绕过它直接捅表。

环境差异:Flight BAPI 的齐备度

不同系统镜像包含的 Flight BAPI 不完全一致。跑 Demo 前先 SE37 搜索 BAPI_SBOOK* / BAPI_FLIGHT* 确认存在;如果你的镜像缺某个,跟着课文学调用模式即可——RETURN 检查 + COMMIT/ROLLBACK 的范式适用于所有 BAPI,第24课综合实战会用课程自建的 zcl_ac_flight_service 封装同样的模式。

时间安排

时段 内容 时长
场景引入 为什么绝不直接 UPDATE 标准表 3 分钟
Demo 跟做 BAPI 创建预订 → 查 RETURN → COMMIT 10 分钟
代码拆解 查找 BAPI / RET2 / 事务控制 / 封装 24 分钟
知识总结 BAPI 调用模板 5 分钟
课后思考 练习 3 分钟

本课目标

完成本课你将能够:

  • 用 BAPI Explorer(事务码 BAPI)和 SE37 搜索定位业务 BAPI;
  • 按标准范式调用 BAPI:填参数 → 调用 → 查 BAPIRET2 → COMMIT/ROLLBACK;
  • 读懂 RET2 的 TYPE/ID/NUMBER/MESSAGE 四件套;
  • 解释 WAIT 参数、批量调用的错误收集模式。

Demo:创建一条航班预订(分步跟做)

SE38 运行 zac_bapi(已随仓库下发):

REPORT zac_bapi.

START-OF-SELECTION.
  " 1. 组装预订数据(结构来自 BAPI 自带的参数类型)
  DATA: lt_booking TYPE TABLE OF bapisbook,
        ls_booking TYPE bapisbook,
        lt_return  TYPE TABLE OF bapiret2,
        ls_return  TYPE bapiret2.

  ls_booking-carrid   = 'AA'.
  ls_booking-connid   = '0017'.
  ls_booking-fldate   = '20260730'.
  ls_booking-bookid   = '00000001'.
  ls_booking-customid = '00000001'.
  ls_booking-class    = 'Y'.
  APPEND ls_booking TO lt_booking.

  " 2. 调用 BAPI
  CALL FUNCTION 'BAPI_SBOOK_CREATE'
    IMPORTING
      booking_number = DATA(lv_bookid)
    TABLES
      booking_data   = lt_booking
      return         = lt_return.

  " 3. 检查 RETURN 表(不是只看出参!)
  LOOP AT lt_return INTO ls_return WHERE type = 'E' OR type = 'A'.
    WRITE: / |错误: { ls_return-message }|.
  ENDLOOP.

  " 4. 成功才提交,失败即回滚——BAPI 的事务铁律
  IF lv_bookid IS NOT INITIAL.
    CALL FUNCTION 'BAPI_TRANSACTION_COMMIT'
      EXPORTING wait = 'X'.
    WRITE: / |预订创建成功! 预订号: { lv_bookid }|.
  ELSE.
    CALL FUNCTION 'BAPI_TRANSACTION_ROLLBACK'.
    WRITE: / '预订创建失败,已回滚'.
  ENDIF.

你会看到什么: 成功路径输出预订号;把 customid 改成不存在的客户再跑,走错误分支回滚——两条路径都要亲手跑一遍,体感"提交/回滚的分水岭"。

知识点

1. BAPI 是什么:规范化的 FM

维度 普通 FM BAPI
本质 Function Module RFC-enabled 的 FM
命名 任意 BAPI_<对象>_<动作>
返回 各式各样 统一 BAPIRET2
事务 内部不定 从不自行 COMMIT,由调用方决定
发布 随意 SAP 官方保证跨版本兼容

一句话:BAPI 是 SAP 承诺"按这个合同调用,升级不坑你"的标准接口。改标准业务数据的唯一正道。

2. 找 BAPI 的三条路

  1. 事务码 BAPI(BAPI Explorer):按业务对象层级浏览(Flight→Booking→Create)——最系统;
  2. SE37 模糊搜索BAPI_SBOOK*BAPI_FLIGHT*
  3. Where-Used 反查:在标准程序里看 SAP 自己怎么调(第1课 Where-Used 技能复用)。

3. BAPIRET2:唯一可信的结果来源

字段 含义
TYPE S 成功 / W 警告 / E 错误 / A 中断
ID / NUMBER 消息类与编号(第18课消息体系)
MESSAGE 拼好的消息文本(V1~V4 是占位变量)
ROW / FIELD 出错的行/字段(批量场景定位用)

判据纪律:成功与否看 RET2 的 TYPE,不要拿"出参非空"当成功——有的 BAPI 失败也回填出参。批量调用时收集全部 E/A 再统一决定提交或回滚。

4. 事务控制:COMMIT 与 WAIT

CALL FUNCTION 'BAPI_TRANSACTION_COMMIT'
  EXPORTING wait = 'X'.        " 同步等待落库再返回
CALL FUNCTION 'BAPI_TRANSACTION_ROLLBACK'.
  • BAPI 是"SAP LUW"的一环:调用后数据处于待提交状态,COMMIT 生效、ROLLBACK 全撤(第5课 LUW 概念的高层封装);
  • WAIT = 'X':等数据库更新线程完成再返回——提交后立刻查询/后续 BAPI 依赖刚写的数据时必须加,否则可能读到旧状态;
  • 忘 COMMIT 的后果:程序看着成功了,对话结束数据被回滚——"幽灵数据"事故第一名。

5. 封装:把 BAPI 藏进类里

课程仓库的全局类 zcl_ac_flight_service(本课引入的全局服务类)就是范例:create_booking( ) 内部完成"调 BAPI → 查 RET2 → 决定 COMMIT/ROLLBACK",把范式固化成一行调用——第24课综合实战直接复用它。范式写一次,业务处只表达意图。

💡 实战经验

直接 UPDATE 标准表是死罪

UPDATE sbook SET ... 绕过了全部业务检查(座位、价格、凭证流),数据一致性当场崩坏,且升级必出问题。改标准业务数据的路径只有一条:BAPI/BDC。这条红线在任何项目规范里都排第一。

批量 BAPI 的两种姿势

有 xxxMULTI 版本的 BAPI 优先(一次传内表);没有就循环调用——但只 COMMIT 一次:循环里逐条 COMMIT 既慢又破坏"整批原子性"。

A 类型消息要当异常处理

RET2 的 TYPE = 'A'(Abort)意味着调用半途被终止,后续状态不可预期——见到 A 与 E 同罪,立即回滚。

📖 延伸阅读

课后思考

把你的回答写在页面底部评论区,注明题号,一起讨论。

  1. 调 BAPI 后忘 COMMIT,程序内看数据"在"、换个会话看"不在"——用 LUW 概念解释这个现象(第5课埋的线)。
  2. WAIT = 'X' 解决什么问题?不加的典型翻车场景是什么?
  3. 批量创建 100 条预订,其中第 37 条 RET2 报 E——你的处理流程是什么?(整批回滚 vs 跳过错行提交其余,两种策略各适合什么业务?)
  4. 动手:把 Demo 改成"失败也输出完整 RET2 明细(含 W 警告)"——把你的 LOOP 写出来。

下一课:第15课:增强(Enhancement)

留言讨论