java Propagation.REQUIRES_NEW不会使用JPA在Spring中创建新事务

avkwfej4  于 2022-11-20  发布在  Java
关注(0)|答案(4)|浏览(176)

我有以下场景。我使用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方法也会回滚,这不是我所需要的。2我需要这两个方法(***createSampleObjectupdateSampleObject*)在任何时候都能被持久化,无论是否抛出异常。3我该如何实现这一点呢?
此外,如果我使用以下语句注解方法createSampleObjectupdateSampleObject

@Transactional(propagation = Propagation.NEVER)

我的想法是抛出一个异常,而我没有得到抛出的异常。2问题出在哪里?3分析日志时我看到这一行:

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

fivyi3re1#

Spring事务是基于代理的。下面是当bean A引起bean B的事务时它是如何工作的。A实际上有一个对代理的引用,代理委托给bean B。这个代理是启动和提交/回滚事务的代理:

A ---> proxy ---> B

在你的代码中,A的一个事务性方法调用A的另一个事务性方法,所以Spring不能拦截这个调用并启动一个新的事务,这是一个不涉及任何代理的常规方法调用。
因此,如果希望启动一个新事务,则方法createSampleObject()应该位于另一个bean中,并注入到当前bean中。
文档中对此进行了详细说明。

6vl6ewon

6vl6ewon2#

我的猜测是,由于这两个方法都在同一个bean中,Spring的AOP没有机会拦截create/updateSampleObject方法调用。

1zmg4dgp

1zmg4dgp3#

请为同一个类(self)创建一个bean,并使用bean.api(需要requires_new)。它可以工作。

vs91vp4v

vs91vp4v4#

在某些情况下,即使您有service a -> service b,并且在service b方法上有@Transactional(propagation = Propagation.REQUIRES_NEW)(顺便说一句,它需要是public!),锁定行等也可能失败。
这通常是在spring(通常是hikari池)数据源配置中没有指定auto-commit: false的情况下,原因是任何select for update或类似的语句都会立即执行,并且数据库不会锁定该行。

相关问题