Vraag waarom rolt transactie terug op RuntimeException maar niet SQLException


Ik heb een door de lente beheerde servicemethode om database-inserts te beheren. Het bevat meerdere invoeginstructies.

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

Ik heb twee eenheidstests die een uitzondering werpen voordat ik de tweede invoeging call. Als de uitzondering een RuntimeException is, wordt de transactie teruggedraaid. Als de uitzondering een SQLException is, blijft de eerste invoeging behouden.

Ik ben verbijsterd. Kan iemand mij vertellen waarom de transactie niet terugdraait op een SQLException? Kan iemand een suggestie geven hoe dit te beheren? Ik kon de SQLException vangen en een RuntimeException gooien, maar dat lijkt gewoon raar.


19
2017-08-19 18:30


oorsprong


antwoorden:


Dit is gedefinieerd gedrag. Van de docs:

Ieder RuntimeException triggers rollback, en elke gecontroleerde uitzondering doet dat niet.

Dit is normaal gedrag bij alle API's met lentetransacties. Standaard als a RuntimeException wordt binnen de transactiecode gegooid, de transactie wordt teruggedraaid. Als een gecontroleerde uitzondering (dus geen RuntimeException) wordt gegooid, dan wordt de transactie niet teruggedraaid.

De reden hiervoor is dat RuntimeException klassen worden in het algemeen genomen in het voorjaar om onherstelbare foutcondities aan te duiden.

Dit gedrag kan worden gewijzigd vanuit de standaardinstelling, als u dit wilt, maar hoe u dit kunt doen, is afhankelijk van hoe u de Spring-API gebruikt en hoe u uw transactiebeheerder instelt.


37
2017-08-19 18:38



Spring maakt uitgebreid gebruik van RuntimeExceptions (inclusief het gebruik van DataAccessExceptions om SQLExceptions of uitzonderingen van ORM's in te pakken) voor gevallen waarin er geen herstel van de uitzondering plaatsvindt. Het gaat ervan uit dat u gecontroleerde uitzonderingen wilt gebruiken voor gevallen waarin een laag boven de service ergens van op de hoogte moet worden gesteld, maar u niet wilt dat de transactie wordt verstoord.

Als u Spring gebruikt, kunt u net zo goed gebruik maken van de jdbc-wrapping-bibliotheken en de DataAccessException-vertaalfaciliteit, het vermindert de hoeveelheid code die u moet onderhouden en geeft zinvollere uitzonderingen. Ook het hebben van een servicelaag met implementatiespecifieke uitzonderingen is een slechte geur. De pre-Spring manier was om implementatie-agnostische gecontroleerde uitzonderingen te maken die implementatiespecifieke uitzonderingen wikkelen, dit resulteerde in veel druk werk en een opgeblazen codebasis. Spring's manier vermijdt die problemen.

Als je wilt weten waarom Spring ervoor heeft gekozen om dingen zo te laten werken, komt dat waarschijnlijk omdat ze AOP gebruiken om de transactie af te handelen. Ze kunnen de handtekening van de methode die ze inpakken niet wijzigen, dus aangevinkte uitzonderingen zijn geen optie.


2
2017-08-19 18:44



Voor @Transactional, rollback gebeurt standaard voor runtime, alleen ongecontroleerde uitzonderingen. Dus uw gecontroleerde uitzondering SQLException veroorzaakt geen terugdraaien van de transactie; het gedrag kan worden geconfigureerd met de rollbackFor en noRollbackFor annotatieparameters.

@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
2017-08-02 05:55