Propagation.REQUIRES_NEW 未使用 JPA 在 Spring 中创建新事务
Propagation.REQUIRES_NEW does not create a new transaction in Spring with JPA
我有以下场景。我正在使用 JPA,Spring:
@Autowired
SampleService service;
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
public void PerformLogic(LogicData data) throws SIASFaultMessage
{
SampleObject so = createSampleObject();
try{
.//do some logic to persist things in data
.
.
persistData(data);
.
.
.
updateSampleObject(so);
}
catch(Exception){
updateSampleObject(so);
throw new SIASFaultMessage();
}
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public createSampleObject()
{
SampleObject so = new SampleObject();
.
.//initialize so
.
service.persist(so);
return so;
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public updateSampleObject(SampleObject so)
{
service.persist(so);
return so;
}
当一切正常时,数据会毫无问题地持久保存在数据库中。但是,当抛出异常时,我需要 updateSampleObject(so) 方法将信息保存在数据库中。这不是正在发生的事情。如果抛出异常,方法 updateSampleObject 也会回滚,这不是我需要的。我需要这两种方法(createSampleObject 和 updateSampleObject ) 一直存在,无论是否抛出异常。
我怎样才能做到这一点?
此外,如果我将方法 createSampleObject 和 updateSampleObject 注释为:
@Transactional(propagation = Propagation.NEVER)
我的想法是抛出一个异常,而我没有抛出任何异常。问题出在哪里?分析日志我看到这一行:
org.springframework.orm.jpa.JpaTransactionManager ==> Creating new transaction with name [com.test.PerformLogic]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT....
这意味着此交易已创建,但我看不到其他交易的提示。
这是我的 Spring 配置文件中关于交易的部分
<bean id="myDataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="myDataSource"/>
<property name="packagesToScan" value="cu.jpa"/>
<property name="persistenceProviderClass" value="org.hibernate.ejb.HibernatePersistence"/>
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">${hdm2ddl.auto}</prop>
</props>
</property>
<property value="/META-INF/jpa-persistence.xml" name="persistenceXmlLocation"/>
<property name="persistenceUnitName" value="jpaPersistenceUnit"/>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
<property name="nestedTransactionAllowed" value="true" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
我的猜测是,由于两个方法都在同一个 bean 中,Spring 的 AOP 没有机会拦截 create/updateSampleObject 方法调用。尝试将方法移动到单独的 bean。
Spring 交易是基于代理的。因此,当 bean A 导致 bean B 发生事务时,它是如何工作的。实际上,A 有一个对代理的引用,该代理委托给 bean B。这个代理是启动和 commits/rollbacks 事务的代理:
A ---> proxy ---> B
在您的代码中,A 的一个事务方法调用了 A 的另一个事务方法。因此 Spring 无法拦截该调用并启动新的事务。这是不涉及任何代理的常规方法调用。
所以,如果你想开始一个新的事务,方法 createSampleObject()
应该在另一个 bean 中,注入你当前的 bean。
这在 the documentation 中有更详细的解释。
请为相同的 class(self) 创建一个 bean 并使用 bean.api(需要 requires_new)。
有用。
我有以下场景。我正在使用 JPA,Spring:
@Autowired
SampleService service;
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
public void PerformLogic(LogicData data) throws SIASFaultMessage
{
SampleObject so = createSampleObject();
try{
.//do some logic to persist things in data
.
.
persistData(data);
.
.
.
updateSampleObject(so);
}
catch(Exception){
updateSampleObject(so);
throw new SIASFaultMessage();
}
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public createSampleObject()
{
SampleObject so = new SampleObject();
.
.//initialize so
.
service.persist(so);
return so;
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public updateSampleObject(SampleObject so)
{
service.persist(so);
return so;
}
当一切正常时,数据会毫无问题地持久保存在数据库中。但是,当抛出异常时,我需要 updateSampleObject(so) 方法将信息保存在数据库中。这不是正在发生的事情。如果抛出异常,方法 updateSampleObject 也会回滚,这不是我需要的。我需要这两种方法(createSampleObject 和 updateSampleObject ) 一直存在,无论是否抛出异常。 我怎样才能做到这一点?
此外,如果我将方法 createSampleObject 和 updateSampleObject 注释为:
@Transactional(propagation = Propagation.NEVER)
我的想法是抛出一个异常,而我没有抛出任何异常。问题出在哪里?分析日志我看到这一行:
org.springframework.orm.jpa.JpaTransactionManager ==> Creating new transaction with name [com.test.PerformLogic]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT....
这意味着此交易已创建,但我看不到其他交易的提示。
这是我的 Spring 配置文件中关于交易的部分
<bean id="myDataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="myDataSource"/>
<property name="packagesToScan" value="cu.jpa"/>
<property name="persistenceProviderClass" value="org.hibernate.ejb.HibernatePersistence"/>
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">${hdm2ddl.auto}</prop>
</props>
</property>
<property value="/META-INF/jpa-persistence.xml" name="persistenceXmlLocation"/>
<property name="persistenceUnitName" value="jpaPersistenceUnit"/>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
<property name="nestedTransactionAllowed" value="true" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
我的猜测是,由于两个方法都在同一个 bean 中,Spring 的 AOP 没有机会拦截 create/updateSampleObject 方法调用。尝试将方法移动到单独的 bean。
Spring 交易是基于代理的。因此,当 bean A 导致 bean B 发生事务时,它是如何工作的。实际上,A 有一个对代理的引用,该代理委托给 bean B。这个代理是启动和 commits/rollbacks 事务的代理:
A ---> proxy ---> B
在您的代码中,A 的一个事务方法调用了 A 的另一个事务方法。因此 Spring 无法拦截该调用并启动新的事务。这是不涉及任何代理的常规方法调用。
所以,如果你想开始一个新的事务,方法 createSampleObject()
应该在另一个 bean 中,注入你当前的 bean。
这在 the documentation 中有更详细的解释。
请为相同的 class(self) 创建一个 bean 并使用 bean.api(需要 requires_new)。 有用。