ロジック:データベースまたはアプリケーション/ 2(制約チェック)

StackOverflow https://stackoverflow.com/questions/167154

  •  03-07-2019
  •  | 
  •  

質問

これは、この質問の特定のバージョンです。
重複した行を挿入しているかどうかを確認したい。アプリケーション層でプログラムで確認する必要があります:

if (exists(obj))
{
    throw new DuplicateObjectException();
}
HibernateSessionFactory.getSession().save(obj);

またはデータベース層によってスローされ、制約に違反したときにトリガーされる例外をキャッチする必要がありますか?

try
{
    HibernateSessionFactory.getSession().save(obj);
}
catch(ConstraintViolationException e)
{
    throw new DuplicateObjectException();
}

編集:言い換えると、制約は残っていますが(とにかく良いデータベース設計であり、自分のアプリがテーブルにアクセスする唯一の人になるかどうかはわかりません)制約に依存し、違反が発生する例外を処理するか、とにかく確認した方が良いですか?

EDIT2:もちろん、トランザクション内でcheck + insertを実行し、テーブルをロックして、その間に他のプロセスが別のレコードを書き込まないようにします

役に立ちましたか?

解決

最初に、この一意性を適切に適用するために、データベースにプライマリキーまたは一意の制約が必要です-質問なし。

制約が存在することを考えると、アプリケーションでどの方法でコーディングする必要がありますか?私の好みは、挿入を試みて例外をキャッチすることです。おそらくほとんどの挿入は成功するため、重複として失敗するのはごくわずかです(これは「例外」が意味することです!):データベースがいずれにせよ独自の制約チェックを実行する場合、すべての挿入の前に存在チェックを実行するのは非効率的です。

また、理論的には、存在チェックが間違っている可能性があります-他の誰かが、存在チェックと挿入の間の短い間隔で同じキー値を持つレコードをコミットする場合。次に、データベース例外をトラップしない場合、実際には挿入されなかったにもかかわらず、挿入が成功したと思われます。

他のヒント

オブジェクトがアプリケーションコードにのみ存在することを確認し、存在しないことに満足したら、オブジェクトを優しく保存します。ただし、別の同時クライアントは、2行のコードの間に独自のオブジェクトを挿入する場合があります。とにかく、Duplicate例外が発生しますが、今回はそれをキャッチしません。

save()を実行して例外をキャッチする必要があります。そうしないと、同じデータベースで動作する他の同時クライアントとの競合状態になります。

データベースに行を挿入する(および行を挿入する)アプリケーションが唯一のものであることが保証できない限り、データベースの例外をキャッチする必要があります。

編集:質問を誤解しているかもしれませんが、オプションB(HibernateSessionFactoryがデータベースからConstraintExceptionをスローする)の方が優れていると主張します。別のアプリケーションが、チェックと実際の関数呼び出しの間の時間の短い間に何かを挿入する可能性は常にわずかです。さらに、だまされていないかどうかを確認する唯一の方法は、追加のクエリを実行することです。これは、パフォーマンスを無駄にするだけです。

質問に対する私の最初の理解は、オプションAで、重複チェックは内部で実行されるということでした(つまり、プログラムが既に作成したデータ構造のみを使用し、INSERTまでクエリを使用しない)。私の元々の答えは、この方法に対する応答でした。

一般に、何か間違ったことをしたためにスローされるエラーに依存するコーディングを避けるようにしています。ただし、場合によってはそれで十分です。あなたの状況では、最初に確認する必要があると思います。

何らかの理由で制約が削除された場合(通常、DBAが再度有効にすることを怠るメンテナンス作業)、これは壊れます(重複エントリを許可します)。アプリケーション内でこの状況を確認する必要があります。

ただし、他の人もデータベースを使用している可能性があるため、データベースに制約を適用させるのはよいことです(ご指摘のとおり)。一般化として、アプリケーションとデータベースはM:M関係にあると想定するのが最善です-これはほとんどの場合に当てはまります。

Hibernate(またはORMコンポーネント)によってスローされる例外は、解釈が難しい傾向があります。

例外に十分な情報があり、実際にユーザーを支援するエラーメッセージを生成できる場合は、例外をキャッチして分析し、先に進みます。

例外に十分な情報がない場合は、エラー状態を確認し、ユーザーに何か間違ったことをしているという有用なエラーメッセージを生成する必要があります。

質問は、「例外はどの程度不透明か」の1つです。かなり不透明なものもあります。他の人は、メッセージ文字列を解析し、ユーザーに何を言うべきかを理解できるのに十分です。

セッションから例外がスローされると、破棄する必要がありますセッション(セクション11.2.3を参照)。したがって、重複をチェックして同じセッションを使用し続ける必要がある場合は、アプリケーションで最初にチェックする以外に選択肢はありません。

また、最初のスニペットのコードには、別のプロセスがレコードを挿入する可能性があり、重複レコードをチェックしてから実際に挿入されるまでの間に重複例外がスローされる可能性があります。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top