Java @Transactional Spring 不创建新事务
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18173623/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
@Transactional Spring not creating a new transaction
提问by Shivam Sinha
Any help with this will be greatly appreciated. Iam using Spring, Jetty(Eclipse Jetty Plugin). It seems like declarative transaction management @Transactional is not working.
对此的任何帮助将不胜感激。我正在使用 Spring、Jetty(Eclipse Jetty 插件)。似乎声明式事务管理 @Transactional 不起作用。
Confirmed this isn't working in two ways: 1. The newly created entity is not flushed into the database after the method call. 2. TransactionSynchronizationManager.isActualTransactionActive(); returns false
确认这不会以两种方式工作: 1. 新创建的实体在方法调用后没有刷新到数据库中。2. TransactionSynchronizationManager.isActualTransactionActive(); 返回假
Note the method below is apart for @Controller class, where a http request calls eventually calls this save method. The controller class does not implement any interfaces. Actual Code:
请注意,下面的方法与 @Controller 类分开,其中 http 请求调用最终会调用此保存方法。控制器类不实现任何接口。实际代码:
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void save(PERule peRule) {
boolean inTransaction = TransactionSynchronizationManager.isActualTransactionActive();
peRuleDAOImpl.persist(peRule);
}
The lack of transaction is also confirm by the Log Output:
缺少交易也由日志输出确认:
DEBUG: org.hibernate.internal.SessionImpl - Opened session at timestamp: 13762325621
DEBUG: org.hibernate.engine.transaction.internal.TransactionCoordinatorImpl - Skipping
JTA sync registration due to auto join checking
DEBUG: org.hibernate.ejb.AbstractEntityManagerImpl - Looking for a JTA transaction to join
DEBUG: org.hibernate.ejb.AbstractEntityManagerImpl - Unable to join JTA transaction
DEBUG: org.hibernate.event.internal.AbstractSaveEventListener - Delaying identity-insert due to no transaction in progress
However when I programatically define explicit transaction boundaries and commit the transaction, the entity is is flushed in to the database. E.g:
但是,当我以编程方式定义显式事务边界并提交事务时,实体被刷新到数据库中。例如:
@Resource
private PlatformTransactionManager txManager;
private void save(PERule peRule) {
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
TransactionStatus status = txManager.getTransaction(def);
def.setName("SomeTxName");
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
try {
peRuleDAOImpl.persist(peRule);
} catch (Exception ex) {
txManager.rollback(status);
}
txManager.commit(status);
}
Hence this doesn't seem to be a problem with the way I defined my transactionManager, since it can be inject into the object as defined above.
因此,这似乎不是我定义 transactionManager 的方式的问题,因为它可以像上面定义的那样注入到对象中。
ContextConfig: root-context.xml
ContextConfig:root-context.xml
<aop:aspectj-autoproxy />
<context:annotation-config />
<context:component-scan
base-package="org.springframework.samples.mvc, com.project.*" />
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>/WEB-INF/spring/proddatabase.properties</value>
</property>
</bean>
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="jdbc/myds" />
</bean>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="persistenceUnitName" value="EconDatesDB" />
<property name="persistenceXmlLocation" value="/WEB-INF/spring/jpa-prod-persistence.xml" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="generateDdl" value="false" />
<property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect" />
</bean>
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.format_sql">false
</prop>
<prop key="hibernate.use_sql_comments">false
</prop>
<prop key="hibernate.generate_statistics">false
</prop>
<prop key="hibernate.transaction.factory_class">org.hibernate.engine.transaction.internal.jta.CMTTransactionFactory
</prop>
<!-- The following line is what's used in Hibernate 4 instead of a TransactionManagerLookup
class -->
<prop key="hibernate.transaction.manager_lookup_class">com.atomikos.icatch.jta.hibernate3.TransactionManagerLookup
</prop>
</props>
</property>
</bean>
<tx:annotation-driven mode="aspectj" proxy-target-class="true" transaction-manager="transactionManager"/>
<bean id="transactionManager"
class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManager" ref="atomikosTransactionManager" />
<property name="userTransaction" ref="atomikosUserTransaction" />
</bean>
<bean id="atomikosUserTransaction" class="com.atomikos.icatch.jta.UserTransactionImp">
<property name="transactionTimeout" value="300" />
</bean>
<!-- Construct Atomikos UserTransactionManager, needed to configure Spring -->
<bean id="atomikosTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager"
init-method="init" destroy-method="close">
<!-- when close is called, should we force transactions to terminate or
not? -->
<property name="forceShutdown" value="false" />
<property name="transactionTimeout" value="300" />
</bean>
<mvc:annotation-driven />
<beans:bean id="conversionService"
class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<beans:property name="formatters">
<beans:bean
class="org.springframework.samples.mvc.convert.MaskFormatAnnotationFormatterFactory" />
</beans:property>
</beans:bean>
<!-- Controllers.xml Only contains routes from path to view name, and has no other spring config
<mvc:view-controller path="showcase/" view-name="/WEB-INF/views/home" /> -->
<beans:import resource="/appServlet/controllers.xml" />
servlet-context:
servlet 上下文:
<resources mapping="/resources/**" location="/resources/" />
<resources mapping="/sharedResources/**" location="/parkingEngine/resources/" />
<beans:bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<beans:property name="order" value="1" />
<!-- <beans:property name="prefix" value="/WEB-INF/views/" /> -->
<beans:property name="prefix" value="" />
<beans:property name="suffix" value=".jsp" />
</beans:bean>
web.xml:
网页.xml:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/root-context.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
pom.xml relevant dependencies:
pom.xml 相关依赖:
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib-nodep</artifactId>
<version>2.2</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.6.10</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.6.10</version>
</dependency>
I have also attempted following variations of tx:annotation-driven in my root-context.xml:
我还尝试在我的 root-context.xml 中使用以下 tx:annotation-driven 变体:
<tx:annotation-driven mode="aspectj" proxy-target-class="true" transaction-manager="transactionManager"/>
<tx:annotation-driven proxy-target-class="true" transaction-manager="transactionManager"/>
<tx:annotation-driven proxy-target-class="true" transaction-manager="transactionManager"/>
<tx:annotation-driven />
采纳答案by JB Nizet
As you noticed, declarative transaction management is AOP based. This means that Spring wraps the transactional beans into a transactional proxy, which takes care of starting and committing transactions. This means that the method call must be intercepted by the proxy in order to be transactional.
正如您所注意到的,声明式事务管理是基于 AOP 的。这意味着 Spring 将事务 bean 包装到事务代理中,该代理负责启动和提交事务。这意味着方法调用必须被代理拦截才能成为事务性的。
It looks like you're calling this method directly from another method of the same bean. In that case, it's a direct call, which doesn't go through the proxy, which thus can't start the transaction:
看起来你是直接从同一个 bean 的另一个方法调用这个方法的。在这种情况下,它是一个直接调用,不通过代理,因此无法启动事务:
HTTP request --> controller.someUnknownMethod() --> controller.save()
The transactional method should be in a separate Spring bean (a service), called by the controller. This will make the call go through the proxy:
事务方法应该在一个单独的 Spring bean(一个服务)中,由控制器调用。这将使调用通过代理:
HTTP request --> controller.someUnknownMethod() --> transactional proxy --> service.save()
This is explained in details in the documentation.