【案例总结】幽灵单据——消失的交货单号
这篇文章应该叫做,《ABAPer在SE37测试BAPI时不COMMIT WORK的后果》
注意:本篇文章的解答是AI deepseek回答的,如有侵权,请立即私聊我,卑微Sesy在线求饶!
目录
背景
解答
一、根本原因分析
二、关键点解读
三、80000001 和 80000002 的命运
结论
80000001 和 80000002 在哪里?
如何避免这种情况?
总结
延申
一、创建测试序列的方法
二、理解 BAPI 的行为
背景
我在SAP系统SE37中测试BAPI:BAPI_OUTB_DELIVERY_CREATE_SLS创建交货单,创建成功,也返回了交货单号80000001,但是我在后台表SE16N :LIKP和LIPS表中都没有查询到。然后我继续使用BAPI创建了交货单号80000002,也是相同结果。后面我使用测试序列,在SE37调用bapi后,继续调用bapi:bapi_TRANSACTION_COMMIT,创建了交货单号80000003,然后commit后,就能够在LIKP和LIPS表中找到80000003这个交货单号了。但是!80000001和80000002这两个交货单号消失了,在任何一个后台表都找不到,所以该如何找到80000001和80000002这两个单据呢?
解答
这个问题非常典型,涉及到 SAP BAPI 执行的核心机制:数据库提交(COMMIT)。
一、根本原因分析
BAPI_OUTB_DELIVERY_CREATE_SLS 的机制:这个 BAPI 的主要功能是在内存(应用服务器缓冲区) 中构建交货单所需的所有数据(抬头 LIKP、行项目 LIPS、相关表数据等)。
当它执行成功时,它会:在内存中生成完整的交货单结构。分配一个交货单号(如 80000001, 80000002)。将这个号码通过 RETURN 参数或 DELIVERY 参数(取决于 BAPI 具体版本和参数设置)返回给调用者。
二、关键点解读
它本身并不执行数据库的写入(INSERT/UPDATE)操作! 它只是准备好数据。
数据库持久化(写入硬盘)需要显式提交:要使 BAPI 在内存中准备的数据真正保存到数据库表(LIKP, LIPS, VBTK 等)中,必须显式地提交数据库事务。
在第三次测试中,我调用了 BAPI_TRANSACTION_COMMIT。这个 BAPI 的作用就是:将当前 SAP LUW (Logical Unit of Work) 中所有未提交的数据库更改(包括BAPI_OUTB_DELIVERY_CREATE_SLS 创建的交货单数据)真正写入数据库。执行一个数据库 COMMIT WORK 操作。
这就是为什么只能在数据库表中看到 80000003。
三、80000001 和 80000002 的命运
当只调用 BAPI_OUTB_DELIVERY_CREATE_SLS 而没有调用 BAPI_TRANSACTION_COMMIT 时:交货单数据(80000001, 80000002)只存在于应用服务器的内存缓冲区中。它们尚未被写入数据库表(LIKP, LIPS)。当会话(Session)结束、退出事务码(如 SE37)、或者系统执行隐式回滚时(例如超时、程序异常终止),SAP 会自动执行一个 ROLLBACK WORK。ROLLBACK WORK 的作用就是撤销当前 SAP LUW 中所有未提交的数据库更改。
因此,80000001 和 80000002 的数据被丢弃了,它们从未真正写入数据库。
结论
80000001 和 80000002 在哪里?
它们不存在于数据库(LIKP, LIPS 或任何相关表)中。 因为没有提交,数据从未写入硬盘。它们也不存在于任何临时表或缓冲区中(在会话结束后)。 回滚操作清除了所有痕迹。简单地说:80000001 和 80000002 被系统“丢弃”了。它们只是短暂存在于内存中但未被持久化的编号。 它们不是有效的、可用的交货单。
如何避免这种情况?
始终在成功调用创建/更改数据的 BAPI 后提交事务:
在 SE37 测试时,使用BAPI_TRANSACTION_COMMIT。
在 ABAP 程序中调用 BAPI 时,在检查 RETURN 参数没有错误消息 (TYPE 不是 'E' 或 'A') 后,调用 COMMIT WORK 语句。
abap代码示例:CALL FUNCTION 'BAPI_OUTB_DELIVERY_CREATE_SLS'EXPORTING...IMPORTING...TABLES...return = lt_return." 检查是否有错误LOOP AT lt_return INTO ls_return WHERE type CA 'EA'.EXIT.ENDLOOP.IF sy-subrc <> 0. " 没有严重错误CALL FUNCTION 'BAPI_TRANSACTION_COMMIT'EXPORTINGwait = 'X'. " 等待提交完成ELSE." 处理错误,通常需要调用 BAPI_TRANSACTION_ROLLBACKCALL FUNCTION 'BAPI_TRANSACTION_ROLLBACK'.ENDIF.
使用测试序列(Test Sequence)功能: 就像第三次测试那样,在 SE37 的测试环境中,可以在调用创建 BAPI 后,紧接着调用 BAPI_TRANSACTION_COMMIT。这是测试这类 BAPI 的标准做法。
总结
80000001 和 80000002 无法找回,因为它们从未被保存到数据库。它们是前两次未提交事务的“幽灵”单据。在 SAP 中,对于创建或修改重要业务数据(如交货单、销售订单、采购订单等)的 BAPI,成功调用 BAPI 并返回成功信息(如单号)只表示数据在内存中准备好了,必须再执行显式的 COMMIT 操作(通过 BAPI_TRANSACTION_COMMIT 或 COMMIT WORK)才能真正写入数据库并生效。 这是 SAP 事务处理机制的核心原则。
延申
一、创建测试序列的方法
在SE37界面,点击功能模块>执行>测试序列
点击测试序列,在弹框中输入函数名称,这里我是测试了BAPI和COMMIT WORK,我的界面如下:
完成后打勾就可以在BAPI调用成功后,进行COMMIT WORK提交了
二、理解 BAPI 的行为
务必查阅 BAPI 的文档(在 SE37 的 Documentation 标签页)。很多创建/更改数据的 BAPI 都需要显式提交。