You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Guidewire Financials支票作废报错Java.Financials.Exception.EmptyTransactionSet求助

Guidewire Financials支票作废异常排查与解决建议

问题背景

在Guidewire Financials系统中,理赔处理人员手动点击「作废支票」按钮后,系统抛出No transactions to save及Java.Financials.Exception.EmptyTransactionSet异常。已知场景:

  • 支票已成功创建,且外部集成确认完成
  • 异常在手动操作约30秒后触发
  • 低环境可断点调试,但无法复现该问题
  • 怀疑问题与CCLocationUtil.runAndCommit()事务处理逻辑相关

作废逻辑代码

function voidCheck() {
  try {
    gw.api.util.CCLocationUtil.runAndCommit({
      if (Check.isInternalCostPayment or Check.isFrontingPayment) {
        Logger.info("Voiding Internal Cost Check" + Check.PublicID)
        Check.voidCheck()
        Check.updateCheckStatus(Check.CheckNumber, Date.CurrentDate.toCalendar(), TransactionStatus.TC_VOIDED)
        Logger.info("Voided Internal Cost Check" + Check.PublicID)
      } else {
        Logger.info("Voiding Check and Triggering Disbursement" + Check.PublicID)
        DisbursementVoidDetails.Instance.invokeVoidService(Check)
        Logger.info("Triggerred Disbursement service and got response" + Check.PublicID)
        Check.voidCheck()
        Logger.info("Check set to Pending void (${Check.Status})")
      }
    }, CurrentLocation)
  } catch (e : IllegalStateException) {
    throw new gw.api.util.DisplayableException(DisplayKey.get("Web.Financials.CheckCancel.Error.IllegalFinancialsStatus"), e)
  } catch (all : Exception){
    Logger.error("Exception encountered during voiding of check: ${Check.PublicID} for claim ${Check.Claim.ClaimNumber} with message ",#voidCheck(),all)
    throw new gw.api.util.DisplayableException(DisplayKey.get("Web.Financials.CheckCancel.Error.void"))
  }
}

排查方向

  • 事务边界与变更有效性:runAndCommit()自动提交事务,需确认闭包内操作是否生成了持久化变更:

    • 检查Check.voidCheck()是否在特定状态(如支票已作废)下不产生数据修改
    • 验证updateCheckStatus是否被voidCheck()内部逻辑覆盖,导致最终无有效变更
    • 排查invokeVoidService外部调用是否耗时过长,引发事务超时或上下文丢失
  • 环境差异分析:对比生产与低环境的核心配置差异:

    • 事务隔离级别(如生产用REPEATABLE READ,低环境用READ COMMITTED)
    • 外部服务响应延迟(生产环境高延迟可能导致事务内操作时序异常)
    • 并发操作情况(生产环境可能有后台任务同时修改Check状态)
  • 日志与调试增强:

    • 在voidCheck()和updateCheckStatus前后添加Check状态、版本号日志,确认数据是否真的被修改
    • 在runAndCommit()闭包末尾输出当前事务变更集:
      def txManager = gw.api.persistence.TransactionManager.current()
      Logger.info("Transaction changes for check ${Check.PublicID}: ${txManager.getChanges()}")
      
    • 单独捕获EmptyTransactionSet异常并添加上下文日志,避免被通用Exception块覆盖
  • runAndCommit()机制验证:确认该方法是否会在无变更时强制提交事务,触发系统级EmptyTransactionSet异常。

解决建议

  1. 拆分事务与外部调用:将invokeVoidService移出runAndCommit()事务块,避免外部调用导致事务超时或上下文问题:

    function voidCheck() {
      try {
        // 先处理外部服务调用,再执行本地事务操作
        if (!Check.isInternalCostPayment && !Check.isFrontingPayment) {
          Logger.info("Triggering Disbursement service for check ${Check.PublicID}")
          DisbursementVoidDetails.Instance.invokeVoidService(Check)
          Logger.info("Disbursement service response received for check ${Check.PublicID}")
        }
    
        gw.api.util.CCLocationUtil.runAndCommit({
          if (Check.isInternalCostPayment or Check.isFrontingPayment) {
            Logger.info("Voiding Internal Cost Check ${Check.PublicID}")
            Check.voidCheck()
            Check.updateCheckStatus(Check.CheckNumber, Date.CurrentDate.toCalendar(), TransactionStatus.TC_VOIDED)
            Logger.info("Internal Cost Check ${Check.PublicID} voided")
          } else {
            Logger.info("Setting check ${Check.PublicID} to pending void")
            Check.voidCheck()
            Logger.info("Check ${Check.PublicID} status: ${Check.Status}")
          }
    
          // 校验变更集,避免空事务提交
          def txManager = gw.api.persistence.TransactionManager.current()
          if (!txManager.getChanges()) {
            Logger.error("No transaction changes detected for check ${Check.PublicID}, aborting commit")
            txManager.rollback()
            throw new gw.api.util.DisplayableException(DisplayKey.get("Web.Financials.CheckCancel.Error.NoChanges"))
          }
        }, CurrentLocation)
      } catch (e : IllegalStateException) {
        throw new gw.api.util.DisplayableException(DisplayKey.get("Web.Financials.CheckCancel.Error.IllegalFinancialsStatus"), e)
      } catch (all : Exception){
        Logger.error("Exception during voiding check ${Check.PublicID} (claim ${Check.Claim.ClaimNumber}): ${all.message}", all)
        throw new gw.api.util.DisplayableException(DisplayKey.get("Web.Financials.CheckCancel.Error.void"))
      }
    }
    
  2. 前置状态校验:在进入事务块前,检查支票状态是否允许作废,避免无效操作:

    if (Check.Status in [TransactionStatus.TC_VOIDED, TransactionStatus.TC_PENDING_VOID]) {
      throw new gw.api.util.DisplayableException(DisplayKey.get("Web.Financials.CheckCancel.Error.AlreadyVoided"))
    }
    
  3. 调整操作顺序:对于内部支付场景,尝试先执行updateCheckStatus再调用voidCheck(),避免状态覆盖导致无变更:

    Check.updateCheckStatus(Check.CheckNumber, Date.CurrentDate.toCalendar(), TransactionStatus.TC_VOIDED)
    Check.voidCheck()
    
  4. 自定义事务校验:在runAndCommit()闭包内主动校验变更集,若为空则回滚并抛出明确业务异常,替代系统级的EmptyTransactionSet异常。


内容的提问来源于stack exchange,提问作者Jakub Petrik

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 15:53:17