1

連続した注文番号で注文を生成する ASP.NET/MSSQL ベースの Web アプリがあります。

ユーザーがフォームを保存すると、次のように新しい注文が作成されます。

  1. order_table から MAX(order_number) を選択し、これを max_order_number と呼びます
  2. set new_order_number = max_order_number + 1
  3. この new_order_number を使用して新しい注文レコードを挿入します (これは注文レコードのフィールドであり、データベース キーではありません)。

上記の 3 つの手順を 1 つのトランザクションに含めた場合、2 人の顧客が同時に新しい注文を保存した場合に、重複する注文番号が作成されることはありませんか? (そして、システムが最終的に複数の IIS サーバーと 1 つの MSSQL サーバーを持つ Web ファーム上にあるとしましょう)。

システムのどこかで同時実行性が原因で、2 人の顧客が同じ MAX(order_number) を選択するのを避けたいと考えています。

どの分離レベルを使用する必要がありますか? ありがとうございました。

4

4 に答える 4

5

注文番号としてIDを使用しないのはなぜですか?

編集:
私が知る限り、現在のorder_number列をIdentityにすることができます(シードをリセットする必要がある場合があります。これを行ってからしばらく経ちます)。あなたはいくつかのテストをしたいかもしれません。これは、SSMSで列をIDに変更したときに実際に何が起こるかについての良い読み物です
作成者は、テーブルにすでに数百万の行がある場合、これに時間がかかる可能性があると述べています。

于 2012-07-25T17:29:42.043 に答える
1

G_M さんに同意します。ID フィールドを使用します。レコードを追加するときは、

INSERT INTO order_table (/* other fields */)
VALUES (/* other fields */) ; SELECT SCOPE_IDENTITY()

Scope Identityからの戻り値が注文番号になります。

于 2012-07-25T17:47:20.317 に答える
1

ID を使用することは、断然最良のアイデアです。次のようにすべてのテーブルを作成します。

CREATE TABLE mytable (
    mytable_id int identity(1, 1) not null primary key,
    name varchar(50)
)

"identity" フラグは、"SQL Server にこの番号を割り当てさせる" ことを意味します。(1, 1) は、ID 番号が 1 から始まり、誰かがテーブルにレコードを挿入するたびに 1 ずつ増えることを意味します。Not Null は、誰もこの列に null を挿入できないことを意味し、「主キー」は、この列にクラスター化インデックスを作成する必要があることを意味します。この種のテーブルでは、次のようにレコードを挿入できます。

-- We don't need to insert into mytable_id column; SQL Server does it for us!
INSERT INTO mytable (name) VALUES ('Bob Roberts')

しかし、あなたの文字通りの質問に答えるために、トランザクションがどのように機能するかについての教訓を与えることができます。最適ではありませんが、これを行うことは確かに可能です。

-- Begin a transaction - this means everything within this region will be 
-- executed atomically, meaning that nothing else can interfere.
BEGIN TRANSACTION
    DECLARE @id bigint

    -- Retrieves the maximum order number from the table
    SELECT @id = MAX(order_number) FROM order_table

    -- While you are in this transaction, no other queries can change the order table,
    -- so this insert statement is guaranteed to succeed
    INSERT INTO order_table (order_number) VALUES (@id + 1)

-- Committing the transaction releases your lock and allows other programs 
-- to work on the order table
COMMIT TRANSACTION

ID主キー列を使用してテーブルを宣言すると、これがすべて自動的に行われることに注意してください。

于 2012-07-25T17:47:45.847 に答える
1

リスクは、2 つのプロセスが MAX(order_number) を選択してから、そのうちの 1 つが新しい注文を挿入することです。より安全な方法は、1 つのステップで行うことです。

INSERT INTO order_table
(order_number, /* other fields */)
VALUES
( (SELECT MAX(order_number)+1 FROM order_table ) order_number,
  /* other values */
)
于 2012-07-25T17:43:02.253 に答える