私はこのようなものを持っています:
_@Service
@Transactional
public class ServiceA {
@Autowired
SomeDAO1 dao1;
@Autowired
ServiceB serviceB;
public void methodServiceA() {
serviceB.someMethodThatRunsInsertIntoDB();
dao1.anotherMethodThatRunsInsertIntoDB();
}
}
@Service
@Transactional
public class ServiceB {
@Autowired
Dao2 dao2;
public void someMethodThatRunsInsertIntoDB() {
dao2.insertXXX();
}
}
_
私の問題は、serviceB.someMethodThatRunsInsertIntoDB()
が正常に実行されたが、dao1.anotherMethodThatRunsInsertIntoDB()
が例外をスローした場合、serviceB
によって行われた変更はロールバックされないということです。 dao1.anotherMethodThatRunsInsertIntoDB()
で例外が発生した場合に備えて、これらの変更をロールバックする必要があります。これどうやってするの?
//編集済み
Spring-servlet.xmlのトランザクション構成
_<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
<property name="jpaDialect">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
</property>
</bean>
_
一方のdaoがEntityManagerを使用し、もう一方のdaoがJdbcTemplateを使用してDBと対話する場合、それは関係がありますか?
// UPDATE-EntityManager構成
_<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true" />
<property name="generateDdl" value="true" />
</bean>
</property>
_
チェックした例外のタイプとともにrollbackFor
パラメータを渡す必要があります。デフォルトでは、チェックされていない例外でのみスプリングがロールバックするようです。詳細: 春のトランザクション:例外またはスロー可能でのロールバック
アノテーション駆動型トランザクション管理を有効にするには、Spring構成ファイル内で<tx:annotation-driven/>
を使用する必要があります。
私の最初の提案は、クラスレベルで本当に必要ない場合は、メソッドレベルで@Transactional
アノテーションを使用することです。
次に、javax.transaction.Transactional
の代わりにorg.springframework.transaction.annotation.Transactional
アノテーションを使用してみてください。Springが自動的に伝播を処理します。
また、@Transactional
を使用する前にトランザクション管理を有効にする必要があります。SpringBootを使用すると、Applicationクラスを@EnableTransactionManagement
でマークするだけで簡単に実行できます。
ただし、必要に応じて、XML構成(<tx:annotation-driven />
)でもこれを確実に行うことができます。詳細については、 http://docs.spring.io/spring-data/jpa/docs/1.11.0.M1/reference/html/#transactions をお読みください。
これは、dao1.anotherMethodThatRunsInsertIntoDB()呼び出しが現在のトランザクション(ServiceAトランザクション)をサポートしていないためです。
ServiceBクラスでは以下の伝播レベルを使用する必要があります。
@Service
@Transactional(propagation = Propagation.REQUIRED)
public class ServiceB {
REQUIRED:Spring REQUIREDの動作は、現在のBeanメソッド実行コンテキストですでに開かれているトランザクションがある場合に同じトランザクションが使用されることを意味します。存在しない場合は、新しいものを作成します。つまり、inner(2nd Transaction)メソッドによってトランザクションがロールバックされた場合、outer(1st Transaction)メソッドはコミットに失敗し、トランザクションもロールバックします。
伝播手段:通常、トランザクションスコープ内で実行されるすべてのコードはそのトランザクションで実行されます。ただし、トランザクションコンテキストがすでに存在する場合に、トランザクションメソッドが実行された場合の動作を指定するオプションがあります。たとえば、コードは既存のトランザクションで実行し続けることができます(一般的なケース)。または、既存のトランザクションを一時停止して、新しいトランザクションを作成することもできます。 Springは、EJBCMTでおなじみのすべてのトランザクション伝播オプションを提供します。 Springでのトランザクション伝播のセマンティクスについては、 トランザクション伝播 を参照してください。
編集済み
注:トランザクションをデフォルトでロールバック状態に設定する唯一の例外は、チェックされていない例外(RuntimeExceptionなど)です。チェックされた例外でトランザクションをロールバックに設定する場合は、そのように構成する必要があります。
@Service
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = YourCheckedException.class))
public class ServiceA {
注:気付いたように、宣言型トランザクション管理はAOPベースです。これは、SpringがトランザクションBeanをトランザクションプロキシにラップし、トランザクションプロキシがトランザクションの開始とコミットを処理することを意味します。これは、トランザクションであるためには、メソッド呼び出しがプロキシによってインターセプトされる必要があることを意味します。 Spring構成ファイルに以下の構成が含まれていることを確認する必要があります。
<tx:annotation-driven transaction-manager="transactionManager" />