【嵌套操作可能引发的问题】原创
金蝶云社区-王尚策
王尚策
44人赞赏了该文章 403次浏览 未经作者许可,禁止转载编辑于2023年08月02日 16:36:40

【背景说明】

K/3 Cloud封装的单据保存、删除、审核、反审核等操作,会自动启动一个事务


操作的标准处理过程如下:


1. 进行操作校验;

2. 触发操作插件 BeforeExecuteOperationTransaction 事件;

3. 启动事务保护(如果外围已经启动了事务,则沿用外围事务)

4. 触发操作插件 BeginOperationTransaction 事件;

5. 执行保存、删除、审核、反审核等操作,对数据库的更新处理;

6. 触发操作插件 EndOperationTransaction 事件;

7. 提交事务;

8. 触发操作插件 AfterExecuteOperationTransaction 事件。


如上,操作插件的 BeginOperationTransaction 、EndOperationTransaction 两个事件,是在事务中的。

如果在此事件中,调用了其他单据的保存、提交等操作,称为嵌套操作。


【嵌套操作可能引发的问题】

嵌套调用的操作,会直接沿用外围操作所启动的事务。如果嵌套操作成功,代码会顺利的回到外围操作代码,随后提交整个事务,完成整个过程,万事大吉。

如果嵌套操作不成功,嵌套操作会自动回滚事务。


注意,此时因为嵌套操作,实际上使用的是外围操作的事务,回滚事务,其实回滚的是外围操作的事务。

回滚事务之后,与数据库的链接自动关闭,此时,要力图避免任何与数据库的交互。

如果此时尝试到数据库读取、存储数据,


即会引发下面这个经典错误:

此操作对该事务的状态无效

The operation is not valid for the state of the transaction.


错误反馈贴:

流程审核的时候,出现  此操作对该事务的状态无效销售出库单审核报错,麻烦谁遇见这个问题给看一下?

流程审核的时候,出现 此操作对该事务的状态无效 (kingdee.com)



典型错误代码:


//保存操作完毕,事务结束之前,进行自动提交、审核
public override void EndOperationTransaction(EndOperationTransactionArgs e)
{
// 取到需要自动提交、审核的单据内码
object[] pkArray = (from p in e.DataEntitys
select p[0]).ToArray();

// 设置提交参数
OperateOption submitOption = OperateOption.Create();
submitOption.SetIgnoreWarning(this.Option.GetIgnoreWarning());
submitOption.SetInteractionFlag(this.Option.GetInteractionFlag());
submitOption.SetIgnoreInteractionFlag(this.Option.GetIgnoreInteractionFlag());


// 创建提交服务
ISubmitService submitService = ServiceHelper.GetService();
IOperationResult submitResult = submitService.Submit(
this.Context, this.BusinessInfo,
pkArray, "Submit", submitOption);


// 未判断提交是否成功,随后直接调用审核操作


// 构建操作可选参数对象
OperateOption auditOption = OperateOption.Create();
auditOption.SetIgnoreWarning(this.Option.GetIgnoreWarning());
auditOption.SetInteractionFlag(this.Option.GetInteractionFlag());
auditOption.SetIgnoreInteractionFlag(this.Option.GetIgnoreInteractionFlag());


// 构建单据主键参数
List> pkEntityIds = new List>();
foreach (var pkValue in pkArray)
{
	pkEntityIds.Add(new KeyValuePair(pkValue, ""));
}
List paras = new List();
paras.Add("1");
paras.Add("");

// 调用审核操作
ISetStatusService setStatusService = ServiceHelper.GetService();


// 如下调用方式,需显示交互信息
IOperationResult auditResult = setStatusService.SetBillStatus(this.Context,this.BusinessInfo,pkEntityIds,paras,"Audit",auditOption);


// 不判断审核是否成功,直接结束,使代码顺利往后执行
}


错误代码说明:

上述代码中,在操作插件的事务内事件EndOperationTransaction中,连续调用了单据的提交、审核操作。

但是并未判断调用的提交、审核操作是否成功。

如果提交操作失败,随后调用审核操作,即会因为外围事务已经回滚,与数据库的链接已经关闭,而引发中断。

此时,正确的做法判断提交操作状态,如果提交失败,即刻把失败原因通过抛出错误的方式给出,并结束流程。对审核操作的处理也一样。

正确处理代码:知识共享 - 保存操作,同时进行自动提交、审核 (kingdee.com)



赞 44