9

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

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

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

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

編集:言い換えると、制約は残っていますが(とにかくデータベース設計は優れており、テーブルにアクセスするのは私のアプリだけかどうかはわかりません)、制約に依存して、その違反を処理しますか?上がるか、とにかくチェックしたほうがいいですか?

EDIT2:もちろん、トランザクション内でチェック+挿入を行い、その間に他のプロセスが別のレコードを書き込んでいないことを確認するためにテーブルをロックします

4

7 に答える 7

8

まず、この一意性を適切に適用するには、データベースに主キーまたは一意性制約を設定する必要があります。これは間違いありません。

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

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

于 2008-10-03T14:44:03.380 に答える
2

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

EDIT: I may have misunderstand the question, but I would still argue that option B (HibernateSessionFactory throws the ConstraintException from the database) is the better option. There's always a small chance that another application could insert something in the sliver of time between your check and the actual function call. In addition, the only way to check for a dupe is to perform an additional query which is just a needless drain on performance.

My original understanding of the question was that in option A the dupe check would be performed internally (i.e. by using only the data structures that the program had already created, and with no query until the INSERT). My original answer was in response to this method.

于 2008-10-03T14:37:45.280 に答える
2

オブジェクトがアプリケーション コードだけに存在することを確認し、存在しないことが確認されたら、オブジェクトを平気で保存します。しかし、別の同時クライアントが、コードの 2 行の間にその瞬間に独自のオブジェクトを挿入する可能性があります。したがって、とにかく重複例外が発生しますが、今回はそれをキャッチしません。

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

于 2008-10-03T16:13:25.710 に答える
1

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

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

于 2008-10-03T14:56:14.960 に答える
1

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

于 2008-10-03T14:36:25.220 に答える
1

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

実際にユーザーに役立つエラー メッセージを生成するのに十分な情報が例外に含まれている場合は、例外をキャッチして分析し、先に進みます。

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

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

于 2008-10-03T15:09:10.990 に答える
0

ハイバネートがセッションから例外をスローしたら、セッションを破棄する必要があります(セクション 11.2.3 を参照)。そのため、重複をチェックして同じセッションを使い続ける必要がある場合は、アプリケーションで最初にチェックするしかありません。

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

于 2008-10-03T15:11:02.327 に答える