why does transaction roll back on RuntimeException but not SQLException

后端 未结 3 524
被撕碎了的回忆
被撕碎了的回忆 2020-12-08 01:22

I have a Spring-managed service method to manage database inserts. It contains multiple insert statements.

@Transactional
public void insertObservation(Obser         


        
相关标签:
3条回答
  • 2020-12-08 01:44

    This is defined behaviour. From the docs:

    Any RuntimeException triggers rollback, and any checked Exception does not.

    This is common behaviour across all Spring transaction APIs. By default, if a RuntimeException is thrown from within the transactional code, the transaction will be rolled back. If a checked exception (i.e. not a RuntimeException) is thrown, then the transaction will not be rolled back.

    The rationale behind this is that RuntimeException classes are generally taken by Spring to denote unrecoverable error conditions.

    This behaviour can be changed from the default, if you wish to do so, but how to do this depends on how you use the Spring API, and how you set up your transaction manager.

    0 讨论(0)
  • 2020-12-08 01:50

    Spring makes extensive use of RuntimeExceptions (including using DataAccessExceptions to wrap SQLExceptions or exceptions from ORMs) for cases where there's no recovering from the exception. It assumes you want to use checked exceptions for cases where a layer above the service needs to be notified of something, but you don't want the transaction to be interfered with.

    If you're using Spring you might as well make use of its jdbc-wrapping libraries and DataAccessException-translating facility, it will reduce the amount of code you have to maintain and provide more meaningful exceptions. Also having a service layer throwing implementation-specific exceptions is a bad smell. The pre-Spring way was to create implementation-agnostic checked exceptions wrapping implementation-specific exceptions, this resulted in a lot of busy-work and a bloated code base. Spring's way avoids those problems.

    If you want to know why Spring chose to make things work this way, it's probably because they use AOP to add the transaction-handling. They can't change the signature of the method they are wrapping, so checked exceptions aren't an option.

    0 讨论(0)
  • 2020-12-08 01:51

    For @Transactional, by default, rollback happens for runtime, unchecked exceptions only. Thus, your checked exception SQLException does not trigger a rollback of the transaction; the behavior can be configured with the rollbackFor and noRollbackFor annotation parameters.

    @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());
    }
    
    0 讨论(0)
提交回复
热议问题