Gov*_*are 0 java spring jpa spring-transactions
我在 JPA 存储库中有两种方法。这两种方法具有传播的水平REQUIRED
的方法是使用利用坚持实体对象Hibernate到Postgresql
@Transactional(propagation = Propagation.REQUIRED)
public void persistEmployee() {
Employee employee = new Employee("Peter", "Washington DC");
entityManager.persist(employee);
try {
persistLineManager();
}
catch( Exception e ) {
// some task
}
}
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = RuntimeException.class)
public void persistLineManager() {
Employee lineManager = new Employee("John", "NYC");
entityManager.persist(lineManager);
if(lineManager != null) // intentionally! To trigger rollback
throw new RuntimeException("Rollback!");
}
Run Code Online (Sandbox Code Playgroud)
根据 Spring 文档,当传播级别为REQUIRED两种方法时,将在同一事务中运行。在我的代码中,我故意抛出 Exception 来触发回滚,但两个实体仍然被持久化。但我相信这两个操作都应该回滚。如果我的理解不正确,请更正,并让我知道回滚这两个操作的正确方法。
PROPAGATION_REQUIRES_NEW:[来自 spring Docs]
PROPAGATION_REQUIRES_NEW,与 PROPAGATION_REQUIRED 相比,为每个受影响的事务范围使用完全独立的事务。在这种情况下,底层物理事务是不同的,因此可以独立提交或回滚,外部事务不受内部事务回滚状态的影响。
在您的服务中,您创建了 2 个方法,都是@Transactional. 当您创建 bean 时,spring 将创建一个代理以在运行时为您添加事务方法的行为。让我们深入了解一下:
该代理由图像说明。来自外部世界的任何呼叫者都不会直接与您交谈,而是与您的代理交谈。然后,代理将调用您执行服务的代码。
现在,“来自外界的任何来电者都不会直接与您交谈”这一点非常重要。如果你进行内部调用,就像你在persistEmployee调用中persistLineManager所做的那样,那么你不会通过代理。您直接调用您的方法,无需代理。因此,persistLineManager不会读取方法顶部的注释。
因此,当persistLineManager抛出 a 时RuntimeException,异常由您的调用者persistEmployee直接捕获,您直接进入您的捕获。由于没有代理,因此没有回滚,因为事务代理没有捕获异常。
如果您只这样做,您将发生回滚:
@Transactional(propagation = Propagation.REQUIRED)
public void persistEmployee() {
Employee employee = new Employee("Peter", "Washington DC");
entityManager.persist(employee);
persistLineManager();
// Don't catch and the exception will be catched by the transaction proxy, which will rollback
}
public void persistLineManager() {
Employee lineManager = new Employee("John", "NYC");
entityManager.persist(lineManager);
if(lineManager != null) // intentionally! To trigger rollback
throw new RuntimeException("Rollback!");
}
Run Code Online (Sandbox Code Playgroud)
默认情况下,@Transactional回滚一个RuntimeException
假设您仍然希望这两种方法独立进行事务处理,您可以做的是使用TransactionTemplate. 下面是一个例子:
class MyService {
// Have a field of type TransactionTemplate
private TransactionTemplate template;
// In the constructor, Spring will inject the correct bean
public MyService(PlatformTransactionManager transactionManager) {
template = new TransactionTemplate(transactionManager);
// Set this here if you always want this behaviour for your programmatic transaction
template.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
}
// Here you start your first transaction when arriving from the outside
@Transactional(propagation = Propagation.REQUIRED)
public void persistEmployee() {
Employee employee = new Employee("Peter", "Washington DC");
entityManager.persist(employee);
// Inner call
try {
persistLineManager();
} catch (RuntimeException e) {
// Do what you want
}
}
public void persistLineManager() {
// Here, ask to your transactionTemplate to execute your code.
template.execute(status -> {
Employee lineManager = new Employee("John", "NYC");
entityManager.persist(lineManager);
if(lineManager != null) // intentionally! To trigger rollback
throw new RuntimeException("Rollback!");
return null;
});
}
}
Run Code Online (Sandbox Code Playgroud)
我还没有测试所有的东西,你可能会遇到一些错误,但我希望你能明白。
让我添加关于 PROPAGATION_REQUIRED 和 PROPAGATION_REQUIRES_NEW 之间区别的最后一部分:
例子:
希望能帮助到你
| 归档时间: |
|
| 查看次数: |
306 次 |
| 最近记录: |