1
私は、行キーがまだ存在しない場合は、行をテーブルに挿入するストアドプロシージャを持っています。select-insertプロシージャでロック・ヒントが必要ですか?
create proc EmployeeInsertIfNotExists
(@id int, @name varchar(50))
as
begin
SET XACT_ABORT ON
begin transaction
if not exists(select * from tbl where id = @id)
insert into tbl(id, name)
values(id, name)
commit transaction
end
このストアドプロシージャは、実際には2つのステートメントで、選択と挿入が可能です。私はトランザクションの内部で両方のステートメントを実行し、その間に何も起こらずに例外が発生するようにします。 id
列は主キーですので、同じIDを2回挿入しないようにしたいと思います。
私の質問は次のとおりです。問題を防ぐために十分な予防措置ですか? select文にヒントを入れる必要はありますか?その場合はHOLDLOCK, TABLOCKX
が必要ですか?これは私にとって新しい材料です。
EDIT:あなたはserializable
へのトランザクション分離レベルをマークしたい
create proc EmployeeInsertIfNotExists
(@id int, @name varchar(50))
as
begin
SET XACT_ABORT ON
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
begin transaction
if not exists(select * from tbl where id = @id)
insert into tbl(id, name)
values(id, name)
commit transaction
end
私は貼り付けた2番目のものに手順を変更する必要がありますか? merge'文を使ってトランザクションを完全に回避することはできますか? – user2023861
はい、2番目のバージョンが動作します。いいえ、マージはアトミックではありません。元のバージョンと同じ問題があります。 –
これは、あなたがやろうとしていることのための方法です。 Serializableはあなたのマシンのパフォーマンスを傷つける(kill?)。 idにユニークな制約がある場合、他の誰もその列に複数のキー値を挿入できないことが保証されます。 procからの戻り値は、挿入が失敗したことを示し、別のキー値で再試行できます。 –