【问题标题】:Using @Transactional(propagation = Propagation.REQUIRES_NEW) in a service throwing Exception affects other associated service with @Transactional在抛出异常的服务中使用 @Transactional(propagation = Propagation.REQUIRES_NEW) 会影响与 @Transactional 关联的其他服务
【发布时间】:2021-10-14 02:20:09
【问题描述】:

我有 service-1 的方法使用 @Transactional 调用 service-2 和 service-3 方法。

现在, Scenario_1(工作场景):

Service-1:

@Transactional
void m1() {
    m2();  // of Service 2  
    m3();  // of Service 3
}

Service-2:
@Transactional(propagation = Propagation.REQUIRES_NEW)
void m2() {
    //1. Insert Employee
}

Service-3:
@Transactional
void m3() {
    // 1. Insert Insurance 
    // 2. Throw RuntimeException
}

Result:
1. Employee inserted
2. Insurance object not inserted (i.e. rolled back)

Scenario_2(未获得预期结果): (将“propagation = Propagation.REQUIRES_NEW”放在 Service-3 方法而不是 Service-2 方法中)

Service-2:
@Transactional
void m2() {
    //1. Insert Employee
}

Service-3:
@Transactional(propagation = Propagation.REQUIRES_NEW)
void m3() {
    // 1. Insert Insurance 
    // 2. Throw RuntimeException
}

Result:
1. Employee not inserted  (why ?)
2. Insurance not inserted (i.e. rolled back)

在 Scenario_2 中,Service-3 中的异常是否会影响(回滚)Service-2,因为 Service-3 正在新事务中运行?我的理解正确还是我遗漏了什么?请提出建议。

以下是实际参考文件(工作场景):

1. OrganzationServiceImpl.java

@Service
public class OrganzationServiceImpl implements OrganizationService {
    @Autowired
    EmployeeService employeeService;

    @Autowired
    HealthInsuranceService healthInsuranceService;

    @Transactional
    @Override
    public void joinOrganization(Employee employee, EmployeeHealthInsurance employeeHealthInsurance) {
        employeeService.insertEmployee(employee);
        healthInsuranceService.registerEmployeeHealthInsurance(employeeHealthInsurance);
    }
}

2. EmployeeServiceImpl.java

@Service
public class EmployeeServiceImpl implements EmployeeService {
    @Autowired
    EmployeeDao employeeDao;

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    @Override
    public void insertEmployee(Employee employee) {
        employeeDao.insertEmployee(employee);
    }   
}

3. HealthInsuranceServiceImpl.java

@Service
public class HealthInsuranceServiceImpl implements HealthInsuranceService {

    @Autowired
    HealthInsuranceDao healthInsuranceDao;

    @Transactional
    @Override
    public void registerEmployeeHealthInsurance(EmployeeHealthInsurance employeeHealthInsurance) {
        healthInsuranceDao.registerEmployeeHealthInsurance(employeeHealthInsurance);
        if (employeeHealthInsurance.getEmpId().equals("emp1")) {
            throw new RuntimeException("thowing RuntimeException for testing");
        }
    }
}

【问题讨论】:

    标签: java spring transactions


    【解决方案1】:

    据我了解,问题在于,在场景 2 中,来自 Service-1 的事务也会回滚,因为您没有处理来自 Service-3 的 RuntimeException。在这种情况下,由于 Service-2 与 Service-2 在同一事务中,因此员工插入被回滚。 这在场景 1 中不会发生,因为您对 Service-2 有单独的事务。

    【讨论】:

    • 感谢@João Dias,在 joinOrganization() 方法中捕获 RuntimeException 可以得到预期的结果。我想知道即使我们不处理它,它也不应该影响场景 2 中的 Service2,因为它在完全不同的事务中运行。我还提到了以下帖子:https://stackoverflow.com/questions/33729810/what-does-suspending-a-transaction-means
    • 但这就是问题所在。在场景 2 中,您有 2 个事务: 1. Service3 由于未捕获 RuntimeException 而回滚。 2. Service1 和 Service2 也因为 Service3 中抛出未捕获的RuntimeException 而回滚。您可以像在 Service2 中使用 @Transactional(propagation = Propagation.REQUIRES_NEW) 一样处理 Service1 中的异常,但您需要考虑这在业务逻辑方面是否有意义。
    • 再次感谢您的清晰解释。我很感激,不幸的是,由于我缺乏所需的声誉点,我无法投票给你的答案。
    • 如果我的回答对您有所帮助,我相信您能够将其标记为“正确”。谢谢。
    猜你喜欢
    • 2017-11-18
    • 2011-10-05
    • 2013-03-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-23
    • 2012-02-19
    相关资源
    最近更新 更多