たとえば、ログに記録して次のリクエストにスキップする、ユーザーにメッセージを表示して次のイベントを処理するなど、すべての失敗を同じ方法で処理したい場合は、未チェックの例外で問題ありません。私のシステムの高レベルで一般的な例外タイプをキャッチし、すべてを同じ方法で処理する必要があります。
しかし、特定の問題から回復したいのですが、チェックされていない例外を使用してそれにアプローチする最善の方法がわかりません。これが具体的な例です。
Struts2 と Hibernate を使用して構築された Web アプリケーションがあるとします。私の「アクション」に例外が発生した場合は、それをログに記録し、かなりの謝罪をユーザーに表示します。しかし、私の Web アプリケーションの機能の 1 つは、一意のユーザー名を必要とする新しいユーザー アカウントを作成することです。ユーザーが既に存在する名前を選択すると、Hibernate はorg.hibernate.exception.ConstraintViolationException
システムの内部で (未チェックの例外) をスローします。この特定の問題から回復したいのですが、ユーザーに別のユーザー名を選択するように依頼するのではなく、同じ「問題をログに記録しましたが、今のところ問題が発生しています」というメッセージを表示するのではありません。
考慮すべきいくつかの点を次に示します。
- 同時にアカウントを作成する人がたくさんいます。名前が存在するかどうかを確認する「SELECT」と、存在しない場合の「INSERT」の間でユーザーテーブル全体をロックしたくありません。リレーショナル データベースの場合、これを回避するためのいくつかのトリックがあるかもしれませんが、私が本当に興味を持っているのは、基本的な競合状態のために例外の事前チェックが機能しない一般的なケースです。ファイルシステムでのファイルの検索などにも同じことが当てはまります。
- "Inc." の技術コラムを読むことによって誘導されたドライブバイ管理に対する私の CTO の傾向を考えると、Hibernate を破棄して Kodo などを使用できるように、永続化メカニズムの周りに間接的なレイヤーが必要です。永続化コードのレイヤー。実際のところ、私のシステムにはそのような抽象化のレイヤーがいくつかあります。チェックされていない例外にもかかわらず、それらがリークするのを防ぐにはどうすればよいですか?
- チェック例外の宣言された弱点の 1 つは、呼び出し元のメソッドがそれらをスローすることを宣言するか、それらをキャッチして処理することにより、スタック上のすべての呼び出しでそれらを「処理」する必要があることです。それらを処理することは、多くの場合、抽象化のレベルに適したタイプの別のチェック済み例外でそれらをラップすることを意味します。したがって、たとえば、チェック例外の土地では、UserRegistry のファイル システム ベースの実装は をキャッチ
IOException
し、データベースの実装は をキャッチしますが、どちらも下層の実装を隠すSQLException
をスローします。UserNotFoundException
未チェックの例外を利用して、実装の詳細を漏らすことなく、各レイヤーでこのラップの負担を軽減するにはどうすればよいですか?