使用spring正确注释Transaction中的传播和隔离

时间:2018-09-19 06:30:16

标签: spring spring-transactions

我写了一个任务调度程序作业,每30分钟为合格的患者生成帐单。在这里,我很困惑,我按照标准保留的传播和隔离级别是否正确。我应该始终将REQUIRES_NEW用作传播的一部分吗?

以下部分的任何建议。

private void startBilling() throws Exception {
    List<Integer> patientIds = null;
    try {
        patientIds = getPatientsForBilling();
        if(null != patientIds) {
            for(Integer patient : patientIds) {
                updatePatientDetails(patient, "STARTED", jdbcTemplate);
                makeBillForPatient(patient, jdbcTemplate);
                updatePatientDetails(patient, "COMPLETED", jdbcTemplate);
            }
        }
    } catch (Exception e) {
         //LOG HERE
         updatePatientDetails(patient, "TERMINATED", jdbcTemplate);
    }
}

@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class,isolation = Isolation.SERIALIZABLE)
private void makeBillForPatient(Integer patient, JdbcTemplate jdbcTemplate2) {
    // A bill for the patient will be generated and printed
}

@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class,isolation = Isolation.SERIALIZABLE)
private void updatePatientDetails(Integer patient,
        String status, JdbcTemplate jdbcTemplate) {
    // Update the patient billing status STARTED
}

@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class,isolation = Isolation.SERIALIZABLE)
private List<Integer> getPatientsForBilling() {
    return new ArrayList<Integer>();
}

这是我已经实现的逻辑

  1. 任务计划程序启动后,它将为所有符合条件的患者(即出院的患者)进行计费
  2. 它将状态更新为STARTED。
  3. 它将生成帐单
  4. 它将状态更新为COMPLETED

任何想法都将不胜感激。

1 个答案:

答案 0 :(得分:0)

实际上,这取决于您的逻辑。据我了解,您将患者标记为“已开始”,然后执行一些可能会长时间运行的复杂任务(创建清单),然后释放患者。

应该将这些动作隔离开来,以便您需要为每个动作单独进行事务处理,在这种情况下,REQUIRES_NEW是可以的。

但是您的逻辑(显示在发布的代码中)有一些泄漏。

想象一下makeBillForPatient()方法调用将引发异常。您遇到的麻烦:

  1. 患者卡在STARTED状态。您需要以某种方式处理保持“开始”状态的患者以重设他们。

  2. 所有其余患者均未得到处理,因为发生异常时您退出了循环。

这样的代码

    patientIds = getPatientsForBilling();
    if(null != patientIds) {
        for(Integer patient : patientIds) {
            try {
                updatePatientDetails(patient, "STARTED", jdbcTemplate);
                try {
                    makeBillForPatient(patient, jdbcTemplate);
                    updatePatientDetails(patient, "COMPLETED", jdbcTemplate);
                } catch (Exception e) {
                    //print something in the log here and reset patient status
                    updatePatientDetails(patient, "INITIAL", jdbcTemplate);
                }
            } catch (Exception e) {
                //print something in the log here
            }
        }
    }

也不要留下空的捕获块。如果出现问题,很难找到源。至少在日志中打印一些内容。