Transaktioner med Spring och JPA

1. Översikt

Denna handledning diskuterar rätt sätt att konfigurera vårtransaktioner , hur man använder @Transactional- anteckningen och vanliga fallgropar.

För en mer djupgående diskussion om kärnan för uthållighetskonfiguration, kolla in våren med JPA-handledning.

I grund och botten finns det två olika sätt att konfigurera Transaktioner - anteckningar och AOP - var och en med sina egna fördelar. Vi ska diskutera den vanligaste kommentar-konfigurationen här.

2. Konfigurera transaktioner

Spring 3.1 introducerar den @EnableTransactionManagement antecknings som vi kan använda i en @Configuration klass och göra det möjligt för transaktions stöd:

@Configuration @EnableTransactionManagement public class PersistenceJPAConfig{ @Bean public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean(){ //... } @Bean public PlatformTransactionManager transactionManager(){ JpaTransactionManager transactionManager = new JpaTransactionManager(); transactionManager.setEntityManagerFactory( entityManagerFactoryBean().getObject() ); return transactionManager; } }

Men om vi använder ett Spring Boot-projekt och har ett fjäder-data- eller fjäder-tx-beroende på klassvägen, är transaktionshantering aktiverad som standard .

3. Konfigurera transaktioner med XML

Innan 3.1 eller om Java inte är ett alternativ, här är XML-konfigurationen, som använder annoteringsdriven och stöd för namnområdet:

4. @Transactional Annotation

Med konfigurerade transaktioner kan vi nu anteckna en böna med @Transactional antingen på klass- eller metodnivå:

@Service @Transactional public class FooService { //... }

Annotationen stöder också ytterligare konfiguration :

  • den Förökning typ av transaktionen
  • den isoleringsnivå för transaktionen
  • en timeout för operationen som omsluts av transaktionen
  • en readOnly-flagga - en ledtråd för uthållighetsleverantören att transaktionen endast ska läsas
  • det återladdning regler för transaktionen

Observera att - som standard sker återställning endast för runtime, endast omarkerade undantag. Det markerade undantaget utlöser inte återföring av transaktionen. Vi kan naturligtvis konfigurera detta beteende med parametrarna för rollbackFor och noRollbackFor .

5. Potentiella fallgropar

5.1. Transaktioner och fullmakter

På en hög nivå skapar Spring proxyservrar för alla klasser som är antecknade med @Transactional - antingen på klassen eller på någon av metoderna. Proxyn tillåter ramverket att infoga transaktionslogik före och efter körmetoden - främst för att starta och begå transaktionen.

Det som är viktigt att komma ihåg är att om transaktionsbönan implementerar ett gränssnitt, kommer proxy som standard att vara en Java Dynamic Proxy. Detta innebär att endast externa metodanrop som kommer in via proxyen kommer att fångas upp. Alla samtal med självinrop startar inte någon transaktion, även om metoden har @Transactional- anteckningen.

En annan varning för att använda proxyservrar är att endast offentliga metoder ska antecknas med @Transactional. Metoder för någon annan synlighet kommer helt enkelt att ignorera kommentaren tyst eftersom dessa inte proxieras.

Den här artikeln diskuterar ytterligare proxying fallgropar i detalj här.

5.2. Ändra isoleringsnivå

Vi kan också ändra transaktionsisoleringsnivån:

@Transactional(isolation = Isolation.SERIALIZABLE)

Observera att detta faktiskt har införts våren 4.1; om vi kör exemplet ovan före våren 4.1 kommer det att resultera i:

org.springframework.transaction.InvalidIsolationLevelException : Standard JPA stöder inte anpassade isoleringsnivåer - använd en speciell JpaDialect för din JPA-implementering

5.3. Skrivskyddade transaktioner

Den Readonly flagga genererar oftast förvirring, speciellt när man arbetar med JPA; från Javadoc:

Detta fungerar bara som en ledtråd för det faktiska transaktionssubsystemet; det kommer inte nödvändigtvis att orsaka fel i skrivåtkomstförsök. En transaktion chef som inte kan tolka skrivskyddade ledtråd kommer inte kasta ett undantag när bad om en skrivskyddad transaktion.

Faktum är att vi inte kan vara säkra på att en infogning eller uppdatering inte kommer att ske när readOnly- flaggan är inställd. Detta beteende är leverantörsberoende, medan JPA är leverantörsagnostiker.

Det är också viktigt att förstå att det Readonly flaggan är endast relevant i en transaktion. Om en operation sker utanför ett transaktionssammanhang ignoreras flaggan helt enkelt. Ett enkelt exempel på det skulle kalla en metod som antecknats med:

@Transactional( propagation = Propagation.SUPPORTS,readOnly = true )

från ett icke-transaktionellt sammanhang - en transaktion skapas inte och flaggan readOnly ignoreras.

5.4. Transaktionsloggning

En användbar metod för att förstå transaktionsrelaterade problem är finjustering av loggning i transaktionspaketen. Det relevanta paketet under våren är ” org.springframework.transaction”, som ska konfigureras med en loggningsnivå för TRACE.

6. Sammanfattning

Vi täckte den grundläggande konfigurationen av transaktionssemantik med både Java och XML, hur man använder @Transactional och bästa praxis i en transaktionsstrategi.

Som alltid finns koden i den här artikeln tillgänglig på Github.