- データベース エンジンはトランザクションをサポートしていません: トランザクションをサポートしていないデータベース エンジンを使用している場合は、Spring トランザクション管理を使用できません。
MySQL を使用し、エンジンが MyISAM である場合、トランザクションは機能しません。MyISAM はトランザクションをサポートしていないため、InnoDB エンジンに変更できます。
- Spring のトランザクション アノテーション @Transactional は、変更されたパブリック メソッドでのみ機能し、他の非パブリック (プライベート、保護された) メソッドに配置された場合、エラーは報告されませんが、トランザクションは機能しません
端的に言うと、AbstractFallbackTransactionAttributeSourceクラスのcomputeTransactionAttributeメソッド内で判定があり、対象のメソッドがpublicでない場合、TransactionAttributeはnullを返す、つまりトランザクションをサポートしていません。
- 例外は正しく処理されません。
この場合、開発者が自分で例外をキャッチし、手動でスローしなかった、つまり例外が飲み込まれたため、Spring トランザクションは当然ロールバックされません。
Spring トランザクションを通常どおりロールバックしたい場合は、処理できる例外をスローする必要があります。例外がスローされない場合、Spring はプログラムが正常であるとみなします。
@Slf4j
@Service
public class UserService {
@Transactional
public void add(UserModel userModel) {
try {
saveData(userModel);
updateData(userModel);
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
}
- Finalで修正したメソッド
最終的に変更されたメソッドは、サブクラスでメソッドを書き換えることができないことを示していますが、
Spring トランザクションの最下層は aop によってプロキシ クラスを作成することになっており、プロキシ クラスはメソッドを書き換えることができず、トランザクション機能を実現できません。
注: メソッドが静的である場合、動的プロキシを介してトランザクション メソッドになることもできません。
@Service
public class UserService {
@Transactional
public final void add(UserModel userModel){
saveData(userModel);
updateData(userModel);
}
}
- Spring の構成が正しくなく、Spring によって管理されていない: Spring 構成ファイルが適切に構成されていない場合 (トランザクション マネージャーが有効になっていない、データ ソースが正しく構成されていないなど)、トランザクションが失敗する可能性があります。
通常の開発プロセスでは、見落とされがちな細部があります。つまり、Spring トランザクションを使用する前提として、オブジェクトは Spring によって管理される必要があり、Bean インスタンスが作成される必要があります。
通常、Bean のインスタンス化と依存関係の注入の機能は、@Controller、@Service、@Component、@Repository などのアノテーションによって自動的に実現できます。
ある日、急いで Service クラスを開発したものの、次のような @Service アノテーションを追加するのを忘れたとしましょう。
//@Service
public class UserService {
@Transactional
public void add(UserModel userModel) {
saveData(userModel);
updateData(userModel);
}
}
上記の例から、UserService クラスに @Service アノテーションが付けられていないことがわかります。その場合、クラスは Spring 管理に渡されないため、その add メソッドはトランザクションを生成しません。
- メソッドの内部呼び出し
@Service
public class ServiceImpl implements Service {
public void test(string xxxx) {
update(xxxx);
}
@Transactional(propagation = Propagation.REQUIRED)
public void update(string xxxx) {
// update logic
}
}
AOP であるため、内部メソッドの直接呼び出しはプロキシ クラスの呼び出しではありません。処理方法の詳細については、サービス トランザクションの最適化 (トランザクションによってメソッドを制御できるか?) を
参照してください。このアプローチでは、循環依存の問題が発生するのではないか。このような疑問を持つ人もいるかもしれません。
答え: いいえ。実際、Spring Ioc 内の 3 レベルのキャッシュがそれを保証しており、循環依存の問題は発生しません。