为什么事务回滚在RuntimeException而不是SQLException

cli*_*unk 25 spring transactions

我有一个Spring管理的服务方法来管理数据库插入.它包含多个插入语句.

@Transactional
public void insertObservation(ObservationWithData ob) throws SQLException 
{
    observationDao.insertObservation(ob.getObservation());
            // aop pointcut inserted here in unit test
    dataDao.insertData(ob.getData());
}
Run Code Online (Sandbox Code Playgroud)

我有两个单元测试,在调用第二个插入之前抛出异常.如果异常是RuntimeException,则回滚事务.如果异常是SQLException,则第一个插入是持久的.

我很困惑.任何人都可以告诉我为什么事务不会回滚SQLException?任何人都可以提出如何管理这个的建议吗?我可以捕获SQLException并抛出RuntimeException,但这看起来很奇怪.

ska*_*man 42

这是定义的行为.来自文档:

任何RuntimeException触发器回滚,任何已检查的异常都不会.

这是所有Spring事务API的常见行为.默认情况下,如果RuntimeException从事务代码中抛出a ,则将回滚事务.如果RuntimeException抛出已检查的异常(即非a ),则不会回滚该事务.

这背后的基本原理是RuntimeExceptionSpring通常采用类来表示不可恢复的错误条件.

如果您希望这样做,可以从默认值更改此行为,但如何执行此操作取决于您使用Spring API的方式以及如何设置事务管理器.

  • 是的,这是正确的,虽然我并不完全理解这一点。我想抛出已检查的 SQLException 以便应用程序代码可以处理它(记录、继续、停止执行等),但我不希望事务成功。我可以将每个事务注释设置为针对异常回滚,但我更愿意设置事务管理器来在应用程序范围内执行该操作。我可以配置基本的 DataSourceTransactionManager 来做到这一点并不是很明显。如果您有对此进行更丰富讨论的建议,我将不胜感激。我现在潜入春季论坛。谢谢! (2认同)

Jus*_*nge 5

对于@Transactional,默认情况下,回滚仅在运行时发生,仅发生未经检查的异常。因此,您检查的异常SQLException不会触发事务的回滚;rollbackFor可以使用和注释参数来配置行为noRollbackFor

@Transactional(rollbackFor = SQLException.class)
public void insertObservation(ObservationWithData ob) throws SQLException 
{
    observationDao.insertObservation(ob.getObservation());
            // aop pointcut inserted here in unit test
    dataDao.insertData(ob.getData());
}
Run Code Online (Sandbox Code Playgroud)