1. 问题背景
在实际的业务开发中,我们经常需要编写批处理程序来自动执行库存移动(例如通过移动类型 311 进行工厂内库位到库位的转储,并涉及批次管理)。 通常,开发顾问会循环调用标准函数 BAPI_GOODSMVT_CREATE 来生成物料凭证。但在这个过程中,经常会遇到一个非常令人头疼的幽灵 Bug。
2. 问题表现
-
单条测试很完美: 在开发环境单独跑一条测试数据,目标库位和目标批次(Destination Batch)都能正确生成。
-
批量运行出大问题: 一旦将多条记录放在一个 Loop 循环中执行,从第二条数据开始,目标批次号就死活赋不上值,或者直接报错,甚至错误地继承了上一条数据的批次信息
3. 原因分析:未清理的“共享餐桌”
这个问题并不是你的传参写错了,而是触发了 SAP 底层的内存交叉污染(Memory Contamination)。
打个比方:
BAPI 的执行就像在餐厅吃饭。正常的流程是:客人吃完离开,服务员把桌子清理干净(清空全局内存),下一拨客人再来吃。 但是,某些老旧的标准 BAPI(特别是在处理批次或复杂库存移动时)存在“清理不干净”的毛病。如果你在同一个程序(同一个 LUW - 逻辑工作单元)里连续调用它,上一次执行时残留在 Function Group 全局变量中的数据,就会干扰下一次的执行逻辑。
在移动类型 311 的场景下,BAPI 内部对目标批次号的校验和取值严重依赖全局缓存,一旦缓存未被正确刷新,就会导致后续的批次赋值失效。
4. 解决方案:使用 DESTINATION 'NONE' 强行隔离内存
既然当前进程的内存脏了洗不干净,那我们就“另起炉灶”。通过将普通的函数调用转变为 本地 RFC 调用(Local RFC Call),强行让 SAP 为每一次 BAPI 执行开启一个全新的、纯净的内存空间。
具体实现步骤如下:
(1) 附加 DESTINATION 'NONE' 调用 BAPI
在调用 BAPI_GOODSMVT_CREATE 时,加上 DESTINATION 'NONE'。这会欺骗系统,让它在当前的同一台应用服务器上,为你开启一个新的内部 RFC 会话(Session)。
ABAP
CALL FUNCTION 'BAPI_GOODSMVT_CREATE'
DESTINATION 'NONE' " << 核心关键:开启独立全新内存空间
EXPORTING
goodsmvt_header = ls_header
goodsmvt_code = ls_code
TABLES
goodsmvt_item = lt_item
return = lt_return.
(2) 在同一次 RFC 会话中提交或回滚
极其重要: 因为你使用了 RFC 开启了新会话,所以后续的 Commit(提交)或 Rollback(回滚)也必须在这个特定的新会话中执行,否则数据不会真正落盘。
ABAP
IF 'no errors'. " 伪代码:如果没有报错
CALL FUNCTION 'BAPI_TRANSACTION_COMMIT'
DESTINATION 'NONE'. " 必须加上 DESTINATION 'NONE'
ELSE.
CALL FUNCTION 'BAPI_TRANSACTION_ROLLBACK'
DESTINATION 'NONE'. " 必须加上 DESTINATION 'NONE'
ENDIF.
(3) 关闭 RFC 连接,释放资源
最后,用完的“炉灶”必须关掉,否则循环次数多了会导致服务器 RFC 资源耗尽(Resource Exhaustion)。
ABAP
CALL FUNCTION 'RFC_CONNECTION_CLOSE'
EXPORTING
destination = 'NONE'.
5. 总结
“DESTINATION 'NONE' + RFC_CONNECTION_CLOSE” 是 ABAP 顾问的终极武器之一。
当你在做批量数据导入或接口开发时,如果在循环调用标准 BAPI、BAPI 扩展或特定事务模块时遇到**“单跑对、群跑错”、“字段莫名丢失”、“状态无故被锁”**的问题,优先考虑是不是全局内存(Global Memory / SAP Memory)串联导致的问题。
采用这种本地 RFC 调用的方式,虽然牺牲了极其微小的通信性能,但能完美实现内存级的数据隔离,彻底解决批次号错乱等诡异现象。
1770

被折叠的 条评论
为什么被折叠?



