web-dev-qa-db-ja.com

Propagation.REQUIRES_NEWは、JPAを使用するSpringで新しいトランザクションを作成しません

次のシナリオがあります。私は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;
}

すべてが正常に機能する場合、データは問題なくデータベースに保持されます。ただし、例外がスローされた場合、メソッドpdateSampleObject(so)がデータベース内の情報を保持する必要があります。これは起こっていることではありません。例外がスローされると、メソッドpdateSampleObjectもロールバックされますが、これは必要ありません。これら2つのメソッド(createSampleObjectおよびupdateSampleObject)例外がスローされたかどうかに関係なく、常に保持されます。どうすればこれを達成できますか?

さらに、メソッドcreateSampleObjectおよびpdateSampleObjectに次のアノテーションを付けると、

@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"/>
14
Alfredo A.

Springトランザクションはプロキシベースです。したがって、Bean AがBean Bのトランザクションを発生させる場合の動作は次のとおりです。Aは実際には、Bean Bに委任するプロキシへの参照を持っています。このプロキシは、トランザクションを開始してコミット/ロールバックするプロキシです。

_A ---> proxy ---> B
_

コードでは、AのトランザクションメソッドがAの別のトランザクションメソッドを呼び出します。そのため、Springは呼び出しをインターセプトして新しいトランザクションを開始できません。これは、プロキシを含まない通常のメソッド呼び出しです。

したがって、新しいトランザクションを開始する場合は、メソッドcreateSampleObject()を別のBeanに入れ、現在のBeanに挿入する必要があります。

これは ドキュメント で詳細に説明されています。

43
JB Nizet

私の推測では、両方のメソッドが同じBeanにあるため、SpringのAOPはcreate/updateSampleObjectメソッドの呼び出しをインターセプトする機会がありません。メソッドを別のBeanに移動してみてください。

9
zmitrok

同じクラス(self)のBeanを作成し、bean.api(requires_newが必要)を使用してください。できます。

0
vasu