于Spring嵌套事务 [英] Nested transaction on Spring
问题描述
我发现了一些奇怪的行为使用嵌套Spring的事务中时:如果在同一个班级,一个方法标注为 @Transactional
调用另一个方法也标注为 @Transactional
不使用第二个注释。
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.
让我们考虑下面的类:
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:
@Entity
public class Pojo {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;
@Override
public String toString() {
return "Pojo: " + id;
}
public int getId() {
return id;
}
}
和字符串部分的applicationContext.xml:
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>
和配置类(我可以在applicationContext.xml中合并本)。
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();
}
}
有关完整性persistence.xml文件:
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 - begin
singleInsert
DEBUG o.h.transaction.JDBCTransaction - commit
Single insert: 1
第二个操作提供了以下的输出:
The second operation gives the following output:
batchInsert
singleInsert
DEBUG o.h.transaction.JDBCTransaction - begin
First insert: 2
singleInsert
Second insert: 3
DEBUG
这是不是我所期望的,因为在 @Transactional注释singleInsert(传播= Propagation.REQUIRES_NEW)
我希望每次调用是要创建一个新的事务不是发生了什么,因为同一个顶层事务用于两个插入。
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:
noTransBatchInsert
singleInsert
DEBUG o.h.e.def.AbstractSaveEventListener - delaying identity-insert due to no transaction in progress
First insert: 0
singleInsert
DEBUG o.h.e.def.AbstractSaveEventListener - delaying identity-insert due to no transaction in progress
Second insert: 0
在 @Configuration
豆春季确保调用同一类中proxified这显然不是这里发生的方法。有没有办法做到改变这种行为?
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?
推荐答案
使用代理
模式AOP的时候,此行为是春天的记录的行为。它可以通过切换到要更改的的AspectJ
这无论是在编译或在运行时执行code仪表模式。
This behavior is the documented behavior of Spring when using the proxy
mode for AOP. It can be changed by switching to the aspectj
mode which perform code instrumentation either on compilation or at runtime.
这篇关于于Spring嵌套事务的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!