SAP小技巧 通过ENQUEUE_READ读取共享锁所著的资源信息
一
前言
在一些自定义程序中,开发有时需要考虑多个用户同时处理同一个事务,在处理过程中对资源的占用.
TIPS
SPRING
这里说的资源是业务层面的资源含义:可以是库存数量, 库存可用量数量,信用限额或者科目预算金额等.
处理过程中临时占用资源,处理结束后,通过单据占用. 如果处理事务异常中止,则释放出占用的资源.
为了说明清楚这个场景, 我们虚拟一个业务需求(该业务需求曾经在某个项目上由业务提出)
二
业务需求说明
科目预算控制:
我们需要为一些重要科目确定一个科目预算金额. 实际创建会计凭证时, 该科目的借方总额不能超过这个预算金额.
三
业务需求实现方案
业务需求的实现根据预算控制精确度或顾问水准,大致可以分为下面三个方案: 这三个方案各有优劣,需要按具体情况选择使用.
(方案中的读取BSEG的借方总额,如果是HANA数据库系统,可以直接用SELECT SUM 读取, 性能很好. 如果非HANA数据系统, 需要考虑优化读取方案.使用科目余额表辅助是一个优化的方式.)
01
初级方案:
在会计凭证增强中检查该科目在表BSEG 中的借方总额, 如果超过了配置表中预算的金额. 则报错.
这个方案中没有考虑当前凭证金额和多用户同时创建对总额的影响.
02
中级方案
在会计凭证增强中检查当前会计凭证中科目的借方金额+该科目在表BSEG中的总额, 如果超过了配置表中的预算的金额. 则报错
该方案考虑了当前凭证对总额的影响,但是没有考虑多个用户同时创建凭证的情况.
如果科目限额 1000 , BSEG 中已经创建了900.此时两个用户同时创建金额为60的凭证. 在中级方案中,这两个用户的凭证可能都会创建成功.最终: 科目限额被超过了20. 再次创建凭证则会失败.
03
高级方案
在会计凭证增强中检查当前会计凭证中的科目金额+该科目在表BSEG 中的总额+其它用户正在处理的金额, 如果超过了配置表中的预算金额. 则报错.
这个方案中考虑了所有可能的情况. 理论上不会出现科目限额超出的情况.
但是该方案有个难点就是怎么获取其它用户正在处理的金额.
如果科目限额 1000 , BSEG 中已经创建了900.此时两个用户同时创建金额为60的凭证. 在高级方案中,这两个用户的凭证只有一个能创建成功.
四
获取其他用户正在处理的金额
加S类型的锁,把公司代码,科目,金额作为锁中的关键字,并用ENQUEUE_READ读取锁内容,是获取其它用户正在处理的金额的最佳方案.
01
添加结构及锁对象
02
获取锁信息
多个用户或进程,可以同时加S类型的锁.加锁信息可以在事务代码SM12中看到
03
ENQUEUE_READ函数
SM12中的锁信息也可以通过函数
ENQUEUE_READ读取
传入要读取的锁名称
执行后可以获取与SM12中同样的结果.
04
解析出结果
传出内表中的字段GARG 串赋值到 ZSHKONT_LOCK 中,可以解析出锁住的科目金额信息
五
高级方案的详细说明
读取科目预算表配置表,如果存在.继续执行增强. 否则退出增强
读取科目BSEG中的借方总额 ,如果已经超过了配置表中的预算额, 报错.
如果没有超过, 先加S锁,锁住当前凭证的金额 锁的_scope参数使用默认值2(更新成功后解锁)
再读取所有用户锁住的金额. 如果BSEG中的借方总额+锁金额合计>限额.报错.
如果没有超出. 则凭证保存成功后,系统会自动解锁.
这样就可以确保科目借方总额不会超过配置的科目预算金额.
六
总结
SAP锁实际是一个逻辑锁: SAP在指定的服务器中开放一个内存区域.
加锁就是在该区域中保存一条记录. 基于锁的类型, 检查该区域中是否存在相同主键的记录.
X 只要存在记录,再次加锁均失败.
E 如果存在记录,并且记录的会话ID与当前加锁的会话ID不一致,则报错. 如果不存在记录,或者会话ID一致,变更加锁次数,返回成功信息
S 不查询记录,直接写入一条新的记录.
借用SAP锁区域,读取S锁的条目并统计其中的数量或金额总额.即可完成读取其他用户占用的资源信息 .
标准可用量占用也使用了类似的逻辑(基于可用量配置确定是否启用锁占用).
锁资源是有限的,一旦锁资源用完,会导致所有需要加锁的应用报错. 实际使用时应避免大量的加锁或者找BASIS增大锁资源的参数.
THE
END
约定
如果你对这篇文章感兴趣,请帮忙点赞,在看,分享.
ABAP开发技巧