私は、アプリケーションの(SQL Serverを使用している)請求書のコレクションには、番号付けにギャップがないことが法的に要求されています。したがって、これらが請求書番号の場合、これは許可されません:[1, 2, 3, 4, 8, 10]
これは順次ではないためです。そのためにはInvoices
テーブルにInvoiceNumber
という列があります。これに加えて、組織ごとに現在の請求書番号を保持するInvoiceNumbers
テーブルがあります(組織ごとに独自のシーケンスが必要なため)。ストアドプロシージャは、InvoiceNumber
をInvoices
に原子的に埋め込む責任があります。 InvoiceNumbers
テーブルで現在のカウンタを1増加させ、その新しい値をInvoices
テーブルに入力するか、エラーが発生した場合にトランザクションをロールバックします。これはうまくいく。競合状態のないSQL Serverで順次請求書番号を作成
新しい要件が追加されました。特定の受注は同じ請求書と同じ請求書番号を共有する必要があります。以前はすべての受注が個別に請求されていました。このため、当日の午前中に請求書を作成し、それを現在のFinancialPeriod
(基本的に勤務日)に関連付けます。これはすべての注文に使用される請求書になります。しかし、組織は共有請求書を必要とするタイプの注文を作成しないため、最初に作成した請求書を浪費する翌日に請求書を作成することはなく、ギャップ。
私にとって最も簡単な解決策は、開始日に作成される共有請求書のInvoiceNumber
を遅延して埋めることでした。その日に注文が作成され、InvoiceNumber
がまだNULL
の場合は、番号を作成します。これにより、InvoiceNumberは決して使用されなくなります(Invoice
レコードが使用されなくなっても意味がありません)。
この目的のために、既存のInvoice
の場合はNULL
の場合にのみ、InvoiceNumber
が入力されます。私はSQL Serverのロック方法と、2つのデータベーストランザクションがであると判断し、競合状態が発生する可能性があるかどうかを確信しており、カウンタを増分して1つの数値を浪費してギャップを作成します。
本質的に、この長い質問は次のように述べられます:2つの同時データベーストランザクションが同じ@invoiceID
のif(@currentNumber is null)
ブロックを入力することができますか?
あなたは私がここから得ているが、私はそれが私の場合に適用されるかわからない参照ロック部:
CREATE PROCEDURE [dbo].[CreateInvoiceNumber]
@invoiceID int,
@appID int
AS
BEGIN
SET NOCOUNT ON;
if not exists (select 1 from InvoiceNumbers where ApplicationID = @appID) insert into InvoiceNumbers values (@appID, 1)
declare @currentNumber int = null;
select @currentNumber = convert(int, i.InvoiceNumber)
from Invoices i
with (HOLDLOCK, ROWLOCK)
where i.ID = @invoiceID
if(@currentNumber is null)
begin
update InvoiceNumbers set @currentNumber = Value = Value + 1
where ApplicationID = @appID
update Invoices set InvoiceNumber = @currentNumber where ID = @invoiceID
end
select convert(nvarchar, @currentNumber)
END
EDIT
で述べたように私のコメント、これらおよびその他の書き込み操作は、C#アプリケーションロジックから開始されたデータベーストランザクションの一部です。デフォルトオプションのSqlConnection
の通常のBeginTransaction
のみです。例外が発生した場合はもちろん、ロールバックされます。
この質問を参照してください。それは、あなたの問題を解決する真実の解決策の答えです。 http://dba.stackexchange.com/questions/36603/handling-concurrent-access-to-a-key-table-without-deadlocks-in-sql-server –
@MaxVernon - 私が間違っている場合は私を修正します。それは私がやっていることをもっとやりたいと思っているようだが、デッドロックを避けて回復することは私の優先事項ではない。いずれにせよ、それは私がこれまでに得たものよりもかなり複雑であるので、私はその答えから必要なものを蒸留するのは難しいです。 – JulianR
だから私は答えとして投稿していない。 –