【问题标题】:Spring can commit Transaction in finally block with RunTimeException in try blockSpring可以在try块中使用RunTimeException在finally块中提交事务
【发布时间】:2012-11-13 15:09:53
【问题描述】:

项目使用了Spring + Hibernate

示例代码:

public void method(){    
   try{  
     dao.saveA(entityA);  
     //condition may be throw RuntimeException;  
     dao.saveB(entityB);  
    }catch(RuntimeException e){  
     throw e;  
    }finally{  
      dao.saveC(entityC)  
    }  
}

最后,只有 entityC 会被保存到数据库中进行测试。
我认为 saveA、saveB、saveC 在同一个事务中,它们不应该被提交。
在这种情况下,我想知道为什么要提交 entityC。
Spring 在 finally 块中是如何做到这一点的?

//----------------------------//
其实我的问题是:spring如何保证finally块中的事务提交。 Spring 会在 finally 块中获得新的连接吗?

【问题讨论】:

  • 事务在哪里管理?为什么说只有C得救,我觉得A和C都有资格得救。 saveB() 是无法访问的代码。这个例子看起来过于简单,以至于它并不是真的有用。这是Java 7吗?他们在 Java 7 中添加了 try-with-resources,因此 try/catch/finally 块的行为有所不同。
  • throw RuntimeException 不会编译,你的意思是不是像 throw new RuntimeException() 这样的?
  • 也许你应该添加关于 RuntimeException 会导致 session 被破坏并且无法使用的信息,所以其他不知道 Rollback异常时的概念,不要迷惑以为你不知道try、catch、finally的概念。

标签: java spring hibernate transactions try-catch-finally


【解决方案1】:

Spring与此无关,你得到的是JLS 14.20.2 Execution of try-catch-finally要求的行为:

通过首先执行try 块来执行带有finally 块的try 语句。那么就有了选择……

  • 如果try 块的执行由于throw 的值V 而突然完成,那么有一个选择:
    如果 V 的运行时类型可分配给try 语句的任何catch 子句的参数,则选择第一个(最左边)这样的catch 子句。 V 值被分配给所选catch 子句的参数,并执行该catch 子句的Block。然后有一个选择...
    • 如果catch 块由于R 原因突然完成,则执行finally 块...

在您的代码 sn-p 中,RuntimeException 对应于上述引用中的“值 V”。

异常被抛出并在各自的catch块中捕获,然后通过重新抛出异常“突然完成” - 也就是说,您的sn-p中的throw e对应于“原因R”在上面的引用中。

然后,按照语言规范的要求,“finally 块被执行”。

【讨论】:

  • 也许这个问题的重点不是 try catch 是如何工作的。但是hibernate如何设法抛出运行时异常但仍然可以保存(而且它可以提交很奇怪)。因为运行时异常会破坏会话。这将导致所有更改回滚,并且无法提交。
猜你喜欢
  • 2017-07-20
  • 2021-12-25
  • 2014-09-12
  • 2015-12-06
  • 2013-12-16
  • 1970-01-01
  • 2018-07-18
相关资源
最近更新 更多