83

SQL Server 2005 データベースへの SQL 挿入を伴う .net トランザクションがあります。テーブルには ID 主キーがあります。

トランザクション内でエラーが発生すると、Rollback()が呼び出されます。行の挿入は正しくロールバックされますが、次にテーブルにデータを挿入すると、ロールバックが発生しなかったかのように ID がインクリメントされます。したがって、本質的に同一性配列にギャップがあります。Rollback()メソッドに不足している ID を再利用させる方法はありますか?

私はこれに正しい方法でアプローチしていませんか?

4

8 に答える 8

113

あなたがそれについて考えるならば、自動インクリメント番号はトランザクションであるべきではありません。他のトランザクションが自動番号が使用されるか「ロールバック」されるかどうかを確認するために待機する必要がある場合、自動番号を使用する既存のトランザクションによってブロックされます。たとえば、ID列に自動番号フィールドを使用するテーブルAを含む以下の疑似コードについて考えてみます。

User 1
------------
begin transaction
insert into A ...
insert into B ...
update C ...
insert into D ...
commit


User 2
-----------
begin transaction
insert into A ...
insert into B ...
commit

ユーザー2のトランザクションがユーザー1の1ミリ秒後に開始する場合、テーブルAへの挿入は、ユーザー1のトランザクション全体が完了するのを待って、Aへの最初の挿入からの自動番号が使用されたかどうかを確認する必要があります。

これは機能であり、バグではありません。厳密に連続している必要がある場合は、別のスキームを使用して自動番号を生成することをお勧めします。

于 2008-11-11T23:24:16.847 に答える
35

アイデンティティの価値がギャップレスであることに依存している場合は、そうです-あなたは間違っています。代理キーの要点は、ビジネス上の意味がないことです。

そして、いいえ、この動作を変更する方法はありません (独自の自動インクリメントをローリングし、他の挿入をブロックすることによるパフォーマンスの影響を受けることを除けば)。

于 2008-11-12T01:11:21.340 に答える
16

DELETE行もすると、シーケンスにギャップが生じます。

シーケンスは一意である必要がありますが、連続している必要はありません。それらが単調に増加しているという事実は、実装の単なるまぐれです。

于 2008-11-11T23:56:53.270 に答える
8

それを心配する必要はなく、ギャップを作るべきだと言う他のすべてのポスターは正しいです。数値にビジネス上の意味があり、その意味がギャップに合わない場合は、ID 列を使用しないでください。

参考までに、何らかの理由でギャップを削除したい場合、ほとんどのデータベースには、自動番号付けを選択した番号に再シードする方法があります。これは面倒なことです。定期的に行う必要がある場合は、上記のように自動番号/ID フィールドを使用しないでください。しかし、SQLサーバーでそれを行うコードは次のとおりです。

DBCC CHECKIDENT('製品', RESEED, 0)

これにより、product テーブルが 1 から始まるように設定されます (ただし、テーブルにレコードがある場合、既に取得されている ID 値は明らかにスキップされます)。他の RDBMS ベンダーには独自の構文がありますが、効果はほぼ同じです。システムのヘルプファイルまたはインターネットで「reseed identity」または「reseed autonumber」を調べてください。

繰り返しますが、これは特別な機会のためのものであり、通常の使用ではありません. それをストアド プロシージャに入れないでください。

于 2008-11-14T02:15:24.013 に答える
6

私が知る限り、挿入する行は自動番号を要求し、ロールバックするとその番号は永久に失われます。シーケンス処理中の自動番号に依存している場合は、使用しているアプローチを検討することをお勧めします。

于 2008-11-11T23:10:40.053 に答える
5

自動番号キーがシーケンシャルである必要はないと思います。実際、次のように要求されることはないと思います。

  • トランザクションaが開始して挿入します

  • トランザクションbが開始し、挿入します

  • トランザクションは中止されます

    あなたは穴を開けます。それについては何もしません。

于 2008-11-11T23:12:24.497 に答える
1

Muhanは、一度に1つではなく、このトランザクションを実行する多数の同時接続のコンテキストでそれを考えようとします。失敗するものもあれば、成功するものもあります。SQL Serverは、ギャップのないID列を維持することではなく、新しい要求が着信したときに実行することに集中する必要があります。IMO it(値のギャップ)は間違いなく時間を費やす価値のないものです。

于 2008-11-11T23:22:39.953 に答える
1

いいえ。シーケンスの実装は自律型トランザクションを使用します。Oracle では、自律型トランザクションは以前は dbms の内部にありましたが、現在は自分で使用できるように公開されています (多くの場合、誤って使用されています)。

PRAGMA AUTONOMOUS_TRANSACTION;' 
于 2008-11-11T23:31:09.047 に答える