我々は持っています:
@Transactional(propagation = Propagation.REQUIRED)
public class MyClass implementes MyInterface { ...
MyInterfaceには、go()
という1つのメソッドがあります。
Go()を実行すると、メソッドが完了したときにコミット/ロールバックする新しいトランザクションを開始します-これで問題ありません。
ここで、go()で、@Transactional(propagation = Propagation.REQUIRES_NEW
を持つMyClassのプライベートメソッドを呼び出してみましょう。 SpringはREQUIRES_NEWアノテーションを「無視」し、新しいトランザクションを開始しないようです。これは、Spring AOPがインターフェイスレベル(MyInterface)で動作し、MyClassメソッドの呼び出しをインターセプトしないためだと考えています。これは正しいです?
Go()トランザクション内で新しいトランザクションを開始する方法はありますか?呼び出す唯一の方法は、anotherREQUIRES_NEWとして設定されたトランザクションを持つSpring管理Beanですか?
更新:クライアントがgo()
を実行するときに、クラスではなくインターフェイスへの参照を介して実行することを追加します。
@Autowired
MyInterface impl;
impl.go();
Springリファレンス2.5から:
プロキシを使用する場合、
@Transactional
注釈は、パブリック可視性を持つメソッドにのみ適用する必要があります。@Transactional
アノテーションで保護されたメソッド、プライベートメソッド、またはパッケージに表示されるメソッドにアノテーションを付けた場合、エラーは発生しませんが、アノテーション付きメソッドは構成済みのトランザクション設定を示しません。
そのため、Springは非パブリックメソッドの@Transactional
アノテーションを無視します。
また、
プロキシモード(デフォルト)では、プロキシを介して着信する「外部」メソッド呼び出しのみがインターセプトされます。つまり、呼び出されたメソッドが
@Transactional
でマークされていても、「自己呼び出し」、つまりターゲットオブジェクト内のメソッドがターゲットオブジェクトの他のメソッドを呼び出すと、実行時に実際のトランザクションにつながりません。
したがって、メソッドpublic
を作成しても、同じクラスのメソッド内からメソッドを呼び出しても、新しいトランザクションは開始されません。
トランザクション設定でaspectj
モードを使用すると、トランザクション関連のコードがクラスに組み込まれ、実行時にプロキシが作成されません。
詳細については、 参照ドキュメント を参照してください。
これを行う別の可能な方法は、クラス自体でクラスのスプリングプロキシを取得し、this
ではなくそのメソッドを呼び出すことです。
@Service
@Transactional(propagation = Propagation.REQUIRED)
public class SomeService {
@Autowired
private ApplicationContext applicationContext;
private SomeService getSpringProxy() {
return applicationContext.getBean(this.getClass());
}
private void doSomeAndThenMore() {
// instead of
// this.doSometingPublicly();
// do the following to run in transaction
getSpringProxy().doSometingPublicly();
}
public void doSometingPublicly() {
//do some transactional stuff here
}
}
@Transactional
は、Spring AOPの動作方法により、public
メソッド上にある場合にのみ気付かれます。
ただし、 プログラムで新しいトランザクションを開始する 必要に応じて、TransactionTemplate
を使用して、たとえば.
TransactionTemplate txTemplate = new TransactionTemplate(txManager);
txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
txTemplate.execute(new TransactionCallback<Object>() {
public Object doInTransaction(TransactionStatus status) {
// do stuff
}
});
要するに、トランザクションの動作を実現するためにプロキシを介してメソッドを呼び出す必要があります。質問で尋ねられたように、同じBeanで「REQUIRES_NEW」を呼び出すことができます。そのためには、「自己」参照を作成する必要があります。春には簡単ではありません。 @Resourceアノテーションを使用して挿入する必要があります。
@Service("someService")
public class ServieImpl implements Service {
@Resource(name = "someService")
Service selfReference;
@Transactional
public void firstMethod() {
selfReference.secondMethod();
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void secondMethod() {
//do in new transaction
}
}
FirstMethodの呼び出しは、「this」ではなくプロキシを呼び出し、「REQUIRES_NEW」トランザクションを機能させる必要があります。