参照 春のドキュメント :
RuntimeExceptionはロールバックをトリガーし、チェックされたExceptionはトリガーしません
未チェックの例外:
- プログラムの欠陥(バグ)を表します-多くの場合、非プライベートメソッドに渡される無効な引数。 Javaプログラミング言語、Gosling、Arnold、Holmesによる: "チェックされていないランタイム例外は、一般的に、プログラムのロジックのエラーを反映し、実行時に合理的に回復できない条件を表します。時間。"
- はRuntimeExceptionのサブクラスであり、通常、IllegalArgumentException、NullPointerException、またはIllegalStateExceptionを使用して実装されます。
- メソッドは、その実装によってスローされたチェックされていない例外のポリシーを確立する義務はありません(ほとんどの場合、そうしません)。
チェックされた例外:
- プログラムの即時制御外の領域での無効な状態を表します(無効なユーザー入力、データベースの問題、ネットワークの停止、ファイルの欠如)
- 例外のサブクラスです
- メソッドは、その実装によってスローされたすべてのチェック済み例外のポリシーを確立する必要があります(チェック済み例外をスタックのさらに上に渡すか、何らかの方法で処理します)。
ビジネスロジック中に問題を発見し、変更をロールバックしたい場合、新しいRuntimeExceptionをスローする必要がありますか?ロジックで識別したので、実際にはRuntimeException(チェックされていない例外)ではありません。それとも私はこれらの概念を誤解していますか?
私の本当の質問、@ Transactionalサービスメソッドでトランザクションをロールバックするためのベストプラクティスは何ですか?
チェックされた例外を使用している場合は、それらを@Transactional
アノテーションのrollbackFor
プロパティに追加するだけです。
@Transactional(rollbackFor = { MyInvalidUserException.class, MyApplicationException.class })
public void method() throws MyInvalidUserException, MyApplicationException {
...
...
}
等.
org.life.Java's回答も正常に機能します。プログラムによるトランザクション管理を宣言型トランザクションに混在させるか、厳密に宣言型に保つかは、学術的な決定です。
次の内部からプログラムでロールバックします。
@Transactional
public void commit() {
try {
// some business logic...
} catch (ConstraintViolationException e) {
// trigger rollback programmatically
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
}
または、ロールバックの例外をマークして、呼び出し元から処理します。
@Transactional(rollBackFor = TransactionException.class)
public void commit() throws ConstraintViolationException{
try {
// some business logic...
} catch (ConstraintViolationException e) {
// handle the exception
// re-throw for rollback
new TransactionException(e);
}
}
public void doCommit(){
try {
commit()
} catch (TransactionException e){
// do nothing as already handled
}
}
コードを単純にするので前者の方が好きですが、Springのドキュメントによると 非推奨 です:
どうしても必要な場合はプログラムによるロールバックを利用できますが、その使用法は、クリーンなPOJOベースのアーキテクチャーの実現に直面しています。
それは次のようになります
@Transactional
public void method () throws YourCustomException {
try{
//logic
}catch(Exception ex){
TransactionAspectSupport.currentTransactionStatus()
.setRollbackOnly();
throw(new YourCustomException(ex.getMessage()));
}
}
どの例外をチェックすべきかについては、さまざまな意見があると言っても過言ではありません。たとえば、 Spring Frameworkの紹介 からのこの抜粋を考えてみましょう:
Springデータアクセス例外階層は、チェックされていない(ランタイム)例外に基づいています。いくつかのプロジェクトでSpringと協力してきたことで、これが正しい決定であるとますます確信しています。
データアクセスの例外は通常は回復できません。たとえば、データベースに接続できない場合、特定のビジネスオブジェクトが問題を回避できない可能性があります。潜在的な例外の1つは楽観的ロック違反ですが、すべてのアプリケーションが楽観的ロックを使用しているわけではありません。賢明に処理できない致命的な例外をキャッチするためにコードを書くことを余儀なくされるのは通常悪いことです。通常、サーブレットやEJBコンテナなどのトップレベルハンドラに伝播させる方が適切です。すべてのSpringデータアクセス例外はDataAccessExceptionのサブクラスであるため、すべてのSpringデータアクセス例外をキャッチすることを選択した場合は、簡単にキャッチできます。
チェックされていないデータアクセス例外から回復したい場合でも、回復できることに注意してください。回復可能な状態のみを処理するコードを書くことができます。たとえば、楽観的ロック違反のみが回復可能であると考える場合、SpringDAOで次のようにコードを記述できます。
try {//作業を行う} catch(OptimisticLockingFailureException ex){//これに興味がある} Springデータアクセスの例外がチェックされている場合は、次のコードを記述する必要があります。とにかくこれを書くことを選ぶことができることに注意してください:
try {//作業を行う} catch(OptimisticLockingFailureException ex){//これに興味がある} catch(DataAccessException ex){//致命的;最初の例に対する1つの潜在的な異議、つまりコンパイラが回復可能な可能性のある例外の処理を強制できないということは、2番目の例にも当てはまります。基本例外(DataAccessException)をキャッチする必要があるため、コンパイラーはサブクラス(OptimisticLockingFailureException)のチェックを強制しません。したがって、コンパイラーは、回復不可能な問題を処理するためのコードを作成するように強制しますが、回復可能な問題に対処するように強制することはできません。
Springによる未チェックのデータアクセス例外の使用は、多くの(おそらくほとんどの)成功した永続化フレームワークの使用と一致しています。 (実際、部分的にJDOに触発されました。)JDBCは、チェックされた例外を使用する数少ないデータアクセスAPIの1つです。たとえば、TopLinkとJDOは、チェックされていない例外を排他的に使用します。 Hibernateは、バージョン3でチェックされた例外からチェックされていない例外に切り替わりました。
データアクセスの例外は明らかにプログラムの直接の制御の範囲外であるため、javapracticesに従って、それらをチェックする必要があります。しかし、春の源の人々は異なります。そして、私は彼らの判断をjavapracticesよりも信頼しています。
したがって、トランザクションをロールバックする必要があることを示すために、チェックされていない例外をスローしても問題はありません。もちろん、チェックされた例外を使用して、それらに対してロールバックするようにアスペクトを構成することもできます。 (詳細については、Affeの回答を参照してください)
チェックされた例外とチェックされていない例外の処理、トランザクションの管理のためにこのURLに出くわしました。これは注釈駆動型のアプローチではありませんが、優れています。