Propagation.REQUIRES_NEW不会在Spring中使用JPA创建新的事务 [英] Propagation.REQUIRES_NEW does not create a new transaction in Spring with JPA

查看:187
本文介绍了Propagation.REQUIRES_NEW不会在Spring中使用JPA创建新的事务的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下情况。我正在使用JPA,Spring:

  @Autowired 
SampleService服务;

@Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
public void PerformLogic(LogicData data)throws SIASFaultMessage
{
SampleObject so = createSampleObject );

尝试{
。//用一些逻辑将数据持久存储在数据
中。

persistData(data);





updateSampleObject(so);
}
catch(Exception){
updateSampleObject(so);
抛出新的SIASFaultMessage();
}

}

@Transactional(传播= Propagation.REQUIRES_NEW)
公共createSampleObject()
{
SampleObject所以= new SampleObject();


。//初始化为


service.persist(so);
回报如此;
}

@Transactional(传播= Propagation.REQUIRES_NEW)
公共updateSampleObject(SampleObject左右)
{
service.persist(左右);
回报如此;
}

当一切正常时,数据保持在数据库中没有问题。但是,当引发异常时,我需要 updateSampleObject(so)方法持久保存数据库中的信息。这不是正在发生的事情。如果抛出异常, updateSampleObject 方法也会回滚,这不是我所需要的。我需要这两个方法( createSampleObject updateSampleObject )始终保持持久,无论是否有例外被抛出或没有。
我该如何实现这一点?



此外,如果我用 createSampleObject updateSampleObject

  @Transactional(propagation = Propagation.NEVER)

这个想法是抛出了一个异常,并且我没有抛出异常。哪里有问题?分析日志我看到这一行:

  org.springframework.orm.jpa.JpaTransactionManager ==>创建具有名称新事务[com.test.PerformLogic]:PROPAGATION_REQUIRED,ISOLATION_DEFAULT .... 



其中意味着这个事务是创建的,但我看不到其他事务的提示。



这是我的配置文件中有关事务的部分

 < bean id =myDataSource
class =org.springframework.jdbc.datasource.DriverManagerDataSource>
< property name =driverClassNamevalue =$ {jdbc.driverClassName}/>
< property name =urlvalue =$ {jdbc.url}/>
< property name =usernamevalue =$ {jdbc.username}/>
< property name =passwordvalue =$ {jdbc.password}/>
< / bean>
< bean id =entityManagerFactory
class =org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean>
< property name =dataSourceref =myDataSource/>
< property name =packagesToScanvalue =cu.jpa/>
< property name =persistenceProviderClassvalue =org.hibernate.ejb.HibernatePersistence/>
< property name =jpaProperties>
<道具>
< prop key =hibernate.dialect> $ {hibernate.dialect}< / prop>
< prop key =hibernate.show_sql> true< / prop>
< prop key =hibernate.hbm2ddl.auto> $ {hdm2ddl.auto}< / prop>
< /道具>
< / property>
< property value =/ META-INF / jpa-persistence.xmlname =persistenceXmlLocation/>
< property name =persistenceUnitNamevalue =jpaPersistenceUnit/>
< / bean>

< bean id =transactionManagerclass =org.springframework.orm.jpa.JpaTransactionManager>
< property name =entityManagerFactoryref =entityManagerFactory/>
< property name =nestedTransactionAllowedvalue =true/>
< / bean>

< tx:注解驱动的事务管理器=transactionManager/>


解决方案

Spring事务是基于代理的。因此,当bean A引发bean B的事务时,它是如何工作的.A实际上有一个对委托给bean B的代理的引用。该代理是启动并提交/回滚事务的代理:

  A --->代理---> B 

在您的代码中,A的事务性方法调用A的另一个事务性方法。 t拦截呼叫并开始新的交易。这是一个没有涉及代理的常规方法调用。因此,如果你想要开始一个新的事务,方法 createSampleObject()应该在另一个bean中,注入到你当前的bean中。



这在文档


I have the following scenario. I am using 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;
}

When everything works fine, data is persisted in database without problems. However, when an exception is thrown, I need that the method updateSampleObject(so) persist the information in the database. This is not what is happening. If an exception is thrown the method updateSampleObject gets rolled back also, which is not what I need. I need that these two methods (createSampleObject and updateSampleObject) get persisted all the time, no matter whether an exception got thrown or not. How can I achieve this?

Moreover, if I anotate the methods createSampleObject and updateSampleObject with:

@Transactional(propagation = Propagation.NEVER)

the idea is that an exception is thrown and I get no exception thrown. Where is the problem? Analizing the logs I see this line:

org.springframework.orm.jpa.JpaTransactionManager  ==> Creating new transaction with name [com.test.PerformLogic]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT....

which means this transaction is created, but I see no hint of the other transaction.

This is the part of my configuration file for Spring regarding transactions

<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"/>

解决方案

Spring transactions are proxy-based. Here's thus how it works when bean A causes a transactional of bean B. A has in fact a reference to a proxy, which delegates to the bean B. This proxy is the one which starts and commits/rollbacks the transaction:

A ---> proxy ---> B

In your code, a transactional method of A calls another transactional method of A. So Spring can't intercept the call and start a new transaction. It's a regular method call without any proxy involved.

So, if you want a new transaction to start, the method createSampleObject() should be in another bean, injected into your current bean.

This is explained with more details in the documentation.

这篇关于Propagation.REQUIRES_NEW不会在Spring中使用JPA创建新的事务的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆