最近在项目中,遇到一个问题。这个问题目前没有找到更好的解决方案,如果各位大神有好的方法,可以评论。
因项目中接口比较多,所以都是通过接口接收数据,然后再做一个alv程序,然后在程序中执行数据的处理。这个模式有效的避免了接口的性能问题,但是也带来了一个新的问题。这个程序执行的时候,数据还没处理完,但是另外一个同事又打开了这个程序,因此导致数据处理的时候,同一个单据,可能会处理两次。因此经过探讨,决定给程序执行的时候,增加锁对象。
开始我们设计的锁对象是在ALV界面上,当用户在ALV上的复选框中勾选的时候,触发DATA_CHANGE事件,然后触发锁定函数,自动上锁,用户取消勾选的时候,再触发解锁函数,解锁当前行。当第一个用户勾选的时候,加上锁,此时第二个用户再想要勾选,则会报错。代码如下:
加锁的代码
解锁的代码
测试运行
初步测试,似乎没什么问题。
但是,后面又暴露出了另外一个问题。
由于这个程序会循环调用migo进行过账,过账之后要调用BAPI:BAPI_TRANSACTION_COMMIT或者BAPI_TRANSACTION_ROLLBACK进行提交数据或回滚,因此当第一个需要过账的单子过完帐之后,提交或者回滚数据的时候,会有CALL FUNCTION 'BUFFER_REFRESH_ALL,会导致程序在ALV界面上加的全部锁对象都释放,另一个用户此时就可以勾选,这样还是会导致凭证重复生成。
后来,和几个开发的同事讨论了一下,找到了两个替代方案。
一、把过账部分的程序另外COPY出来,做一个过账处理程序,原来程序走到过账的时候,通过SUBMIT或者CALL TRANSCATION的方式,调用过账处理程序,这样的话,即可有效避免由于数据提交导致的锁对象失效的问题,缺点在于,有的时候,需要得到过账的返回结果在取数的那个程序上显示出来,但是通过此方法得不到过账的结果,具体代码没有写,有兴趣的同学可以测试。
二、在用户在调用BAPI进行过账之前,锁定数据,此时需要注意的是,需要在之前增加校验逻辑,判断当前单据是否已经过账,如果已经过账,则直接返回过账结果,如果没有过账,则锁定单据,并且过账,等调用完BAPI之后,等待自动解锁。此方案的问题是,会有效率上的问题需要处理。
目前采用了第二个解决方案,欢迎各位大神给出新的思路,能彻底解决这个问题。