2013-11-25 54 views
8

我有一个JavaEE应用程序使用Hibernate连接到数据库。在我的应用程序的某些部分,我调用了具有@Transactional注释的方法。在其中一些情况下,我想回滚整个事务(外部服务方法调用和内部)。在某些情况下,我只想回滚内部服务方法调用(即回滚到在内部方法开始时定义的保存点)。如何使用休眠回滚到保存点嵌套事务

第一部分已经存在,但第二部分有问题。当我执行以下操作时,出现“UnexpectedRollbackException”,并显示消息“事务已回滚,因为它已被标记为仅回退”。

@Service 
public class OuterService{ 

    @AutoWired 
    private InnerServcie innerService; 

    @Transactional 
    public void outer(){ 
     try{ 
      innerService.inner(); 
     }catch(RuntimeException e){ 
      //if i dont throw this up, it will give me the "UnexpectedRollbackException" 
      System.out.println("I cought a RuntimeException"); 
     } 
    } 
} 

@Service 
public class InnerServcie{ 
    @Transactional 
    public void inner(){ 
     //here we insert some data into db using hibernate 
     //but something goes wrong and an exception is thrown 
    } 
} 

回答

0

在Spring/Hibernate/Java EE中不支持嵌套事务。因此,无论是整个事务都被回滚,还是内部事务实际上都是一个新的,不同的事务,只要它成功,即使外部事务稍后回滚,它也会立即提交。

如果是后者,你想要什么,然后只需用

@Transactional(propagation = Propagation.REQUIRES_NEW) 
+0

我已将此添加到内部方法,我也得到一个僵局!有任何想法吗? – hfm

6

您正在查找的功能称为保存点。它们并非严格地说是嵌套事务,而是后续SQL指令链中的里程碑,您可以将其回滚。回滚到保存点表示无效从创建保存点开始发出的所有指令,因此您可以拥有多个保存点,但您只能回退现在保存点之间的指令,而不是在2个保存点之间!

弹簧支持保存点,手动使用JdbcTransactionObjectSupport和使用@Transactional注释。

根据文件http://docs.spring.io/spring/docs/2.5.3/reference/transaction.html要点9.5.7.3您应该使用Propagation.NESTED

但是,该选项可能不适用于您的情况。来自Javadoc:

注意:实际创建嵌套事务只能在 特定事务管理器上工作。开箱即用,这仅适用于在处理JDBC 3.0 驱动程序时使用的JDBC DataSourceTransactionManager的 。一些JTA提供者也可能支持嵌套事务。

作为最后的手段,您可以直接发出启动/回滚到保存点的SQL指令。

对于PostgreSQL这将是:

SAVEPOINT foo; 

ROLLBACK TO SAVEPOINT foo; 

来源:http://www.postgresql.org/docs/8.2/static/sql-rollback-to.html