Quantcast
Channel: Nested transaction on Spring - Stack Overflow
Viewing all articles
Browse latest Browse all 4

Nested transaction on Spring

$
0
0

I found some strange behavior when using nested Spring transactions: when, in the same class, a method annotated as @Transactional calls another method also annotated as @Transactional the second annotation is not used.

Let's consider the following class:

public class Main {    public static void main(String[] args) {        ApplicationContext context = new AnnotationConfigApplicationContext(Config.class);        final Main main = context.getBean(Main.class);        // First Op        System.out.println("Single insert: "+ main.singleInsert());        // Second Op        main.batchInsert();        // Third Op        main.noTransBatchInsert();    }    @PersistenceContext    private EntityManager pm;    @Transactional(propagation=Propagation.REQUIRED)    public void batchInsert() {        System.out.println("batchInsert");        System.out.println("First insert: "+ singleInsert());        System.out.println("Second insert: "+ singleInsert());    }    public void noTransBatchInsert() {        System.out.println("noTransBatchInsert");        System.out.println("First insert: "+ singleInsert());        System.out.println("Second insert: "+ singleInsert());    }    @Transactional(propagation=Propagation.REQUIRES_NEW)    public int singleInsert() {        System.out.println("singleInsert");        Pojo p = new Pojo();        pm.persist(p);        return p.getId();    }}

The entity if the following class:

@Entitypublic class Pojo {    @Id    @GeneratedValue(strategy = GenerationType.AUTO)    private int id;    @Override    public String toString() {        return "Pojo: "+ id;    }    public int getId() {        return id;    }}

and the String parts applicationContext.xml:

<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop"    xmlns:context="http://www.springframework.org/schema/context" xmlns:jee="http://www.springframework.org/schema/jee"    xmlns:tx="http://www.springframework.org/schema/tx" xmlns:task="http://www.springframework.org/schema/task"    xsi:schemaLocation="   http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd   http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd   http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd   http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd   http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd   http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd"><tx:annotation-driven /><bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean"><property name="persistenceUnitName" value="MyPersistenceUnit" /></bean><bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"><property name="entityManagerFactory" ref="entityManagerFactory" /></bean></beans>

and the configuration class (I could have merge this in applicationContext.xml).

@Configuration@ImportResource("/META-INF/applicationContext.xml")public class Config {    @Bean    public Main main() {        return new Main();    }}

For completeness the persistence.xml file:

<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd" version="2.0"><persistence-unit name="MyPersistenceUnit" transaction-type="RESOURCE_LOCAL"><provider>org.hibernate.ejb.HibernatePersistence</provider><properties><property name="hibernate.hbm2ddl.auto" value="create" /><property name="hibernate.show_sql" value="true" /><property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect" /><property name="hibernate.connection.driver_class" value="org.h2.Driver" /><property name="hibernate.connection.url" value="jdbc:h2:mem:TestDSJPA2;DB_CLOSE_DELAY=-1;LOCK_MODE=0" /><!--<property name="hibernate.connection.url" value="jdbc:h2:mem:TestDSJPA2;DB_CLOSE_DELAY=-1;LOCK_MODE=0" />--><property name="hibernate.connection.username" value="sa" /><property name="hibernate.connection.password" value="" /><property name="hibernate.connection.autocommit" value="false"/><property name="hibernate.c3p0.min_size" value="5" /><property name="hibernate.c3p0.max_size" value="20" /><property name="hibernate.c3p0.timeout" value="300" /><property name="hibernate.c3p0.max_statements" value="50" /><property name="hibernate.c3p0.idle_test_period" value="3000" /></properties></persistence-unit></persistence>

So in the main class, the first operation is performed as expected that is in a new transaction. The output (including some DEBUG messages) is:

DEBUG o.h.transaction.JDBCTransaction  - beginsingleInsertDEBUG o.h.transaction.JDBCTransaction  - commitSingle insert: 1

The second operation gives the following output:

batchInsertsingleInsertDEBUG o.h.transaction.JDBCTransaction  - beginFirst insert: 2singleInsertSecond insert: 3DEBUG

This is not what I expected since in annotating singleInsert with @Transactional(propagation=Propagation.REQUIRES_NEW) I would expect a new transaction to be created for every call which is not what's happening since the same top level transaction is used for both insertion.

The third operation fails as well as no transaction is created at all:

noTransBatchInsertsingleInsertDEBUG o.h.e.def.AbstractSaveEventListener  - delaying identity-insert due to no transaction in progressFirst insert: 0singleInsertDEBUG o.h.e.def.AbstractSaveEventListener  - delaying identity-insert due to no transaction in progressSecond insert: 0

In the @Configuration beans Spring ensures that calls to the method on the same class are proxified which is obviously not happening here. Is there a way do change this behavior?


Viewing all articles
Browse latest Browse all 4

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>