いくつかのコマンドを実行するストアドプロシージャがあります。これらのコマンドがストアドプロシージャのトランザクションにラップされないようにします。4番目のコマンドが失敗した場合、1番目、2番目、および3番目のコマンドをロールバックではなく、そのままにしておきます。
すべてが1つの大きなトランザクションとして実行されないような方法でストアドプロシージャを記述することは可能ですか?
いくつかのコマンドを実行するストアドプロシージャがあります。これらのコマンドがストアドプロシージャのトランザクションにラップされないようにします。4番目のコマンドが失敗した場合、1番目、2番目、および3番目のコマンドをロールバックではなく、そのままにしておきます。
すべてが1つの大きなトランザクションとして実行されないような方法でストアドプロシージャを記述することは可能ですか?
回答:
すべてのトランザクションが単一のトランザクションで実行されるわけではありません。この例を見てください:
use TestDB;
go
if exists (select 1 from sys.tables where object_id = object_id('dbo.TestTranTable1'))
drop table dbo.TestTranTable1;
create table dbo.TestTranTable1
(
id int identity(1, 1) not null,
some_int int not null
default 1
);
go
insert into dbo.TestTranTable1
default values;
go 4
select *
from dbo.TestTranTable1;
if exists (select 1 from sys.sql_modules where object_id = object_id('dbo.ChangeValues'))
begin
drop proc dbo.ChangeValues;
end
go
create proc dbo.ChangeValues
as
update dbo.TestTranTable1
set some_int = 11
where id = 1;
update dbo.TestTranTable1
set some_int = 12
where id = 2;
update dbo.TestTranTable1
set some_int = 13
where id = 3;
-- this will error out (arithmetic overflow)
update dbo.TestTranTable1
set some_int = 2147483648
where id = 4;
go
exec dbo.ChangeValues;
select *
from dbo.TestTranTable1;
出力は次のとおりです。
イベントを監視する拡張イベントセッションを作成することによりsql_transaction
、実行からの出力はdbo.ChangeValues
次のとおりです。
上記のスクリーンショットでわかるように、4つのステートメントのそれぞれに個別のトランザクションがあります。最初の3つはコミットし、最後の1つはエラーのためロールバックします。
ここではバッチとトランザクションに関して何らかの混乱があると思います。
トランザクションは、いずれかの単位として成功または失敗するステートメントのステートメントまたはセットです。すべてのDDLステートメントはトランザクション自体にあります(つまり、100行を更新しても行98がエラーをスローした場合、行は更新されません)。トランザクション内で一連のステートメントをラップすることもできBEGIN TRANSACTION
ます。次に、COMMIT
またはを使用しますROLLBACK
。
バッチが一緒に実行される一連のステートメントです。ストアドプロシージャはバッチの例です。ストアドプロシージャでは、1つのステートメントが失敗し、エラートラップ(通常はTRY/CATCH
ブロック)がある場合、後続のステートメントは実行されません。
ストアドプロシージャ自体または外部スコープ(アプリケーションまたはこのプロシージャを呼び出すストアドプロシージャなど)にエラーがトラップされているため、エラーが発生したときにバッチがキャンセルされていると思われます。その場合、エラーをトラップしているスコープでエラーを処理する方法を調整する必要があるため、これを解決するのは難しくなります。
SQLサーバーのすべてがトランザクションに含まれています。
明示的に指定begin transaction
しend transaction
、明示的トランザクションと呼ばれる場合。いけないときは、暗黙のトランザクションです。
現在のモードを切り替えるには、次を使用します
set implicit_transactions on
または
set implicit_transactions off
select @@OPTIONS & 2
上記が2を返す場合、暗黙のトランザクションモードになっています。0が返された場合、自動コミットされています。
トランザクションは、データベースを一貫した状態に維持するために、ALLまたはゼロです。ACIDプロパティを記憶します。
CREATE TABLE [dbo].[Products](
[ProductID] [int] NOT NULL,
[ProductName] [varchar](25) NULL,
[DatabaseName] [sysname] NOT NULL,
CONSTRAINT [pk_Product_ID_ServerName] PRIMARY KEY CLUSTERED
(
[ProductID] ASC,
[DatabaseName] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
-- insert some data
INSERT INTO [dbo].[Products]([ProductID], [ProductName], [DatabaseName])
SELECT 1, N'repl1_product1', N'repl1' UNION ALL
SELECT 1, N'repl2_product1_02', N'repl2' UNION ALL
SELECT 1, N'repl3_product1_03', N'repl3' UNION ALL
SELECT 2, N'repl1_product1_01', N'repl1' UNION ALL
SELECT 2, N'repl2_product1', N'repl2' UNION ALL
SELECT 2, N'repl3_product1_03', N'repl3' UNION ALL
SELECT 3, N'repl1_product1_01', N'repl1' UNION ALL
SELECT 3, N'repl2_product1_02', N'repl2' UNION ALL
SELECT 3, N'repl3_product1', N'repl3' UNION ALL
SELECT 4, N'repl1_product1_01', N'repl1' UNION ALL
SELECT 4, N'repl2_product1_02', N'repl2' UNION ALL
SELECT 5, N'repl1_product1_01', N'repl1' UNION ALL
SELECT 5, N'repl2_product1_02', N'repl2'
-今すぐSPを作成-最初の3つは成功し、4つ目は文字列の切り捨てにより失敗することに注意してください...
IF OBJECT_ID ('usp_UpdateProducts', 'P') IS NOT NULL
DROP PROCEDURE usp_UpdateProducts;
GO
create procedure usp_UpdateProducts
as
begin try
update Products
set ProductName = 'repl1_product1'
where DatabaseName = 'repl1'and ProductID = 1;
update Products
set ProductName = 'repl2_product1'
where DatabaseName = 'repl2' and ProductID = 2;
update Products
set ProductName = 'repl3_product1'
where DatabaseName = 'repl3' and ProductID = 3;
update Products
set ProductName = 'repl3_product1_03&&&&&&&&&&39399338492w9924389234923482' -- this will fail ...
where DatabaseName = 'repl3' and ProductID = 4;
SELECT 1/0;
end try
begin catch
SELECT
ERROR_NUMBER() AS ErrorNumber,
ERROR_SEVERITY() AS ErrorSeverity,
ERROR_STATE() as ErrorState,
ERROR_PROCEDURE() as ErrorProcedure,
ERROR_LINE() as ErrorLine,
ERROR_MESSAGE() as ErrorMessage;
end catch
go
コマンドごとに個別のトランザクションが必要になります。保存されたトランザクションでもこれを実現できます。
SAVE TRANSACTION (Transact-SQL)
製品ドキュメントを参照してください。
すべてのステートメントは暗黙的なトランザクションにラップされているため、個々のトランザクションをストアドプロシージャのデフォルトの動作に限定します。ただし、コードの運命を制御するために暗黙のトランザクションに依存することはできません。本番コードでのトランザクションの処理方法を明示的に制御することをお勧めします。
各部分をBEGIN TRANで区切り、トランザクションが成功したかどうかを確認します。それがコミットされた場合、そうでない場合はロールバックを行います。すべて同じレベルから実行されているため、1つのセクションが失敗してもロールバックすることなく各セクションを個別にコミットできます。
詳細については、http://msdn.microsoft.com/en-us/library/ms188929.aspxをご覧ください。