답변:
모든 트랜잭션이 단일 트랜잭션에서 실행되지는 않습니다. 이 예제를 살펴보십시오.
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
.
위의 스크린 샷에서 볼 수 있듯이 네 가지 진술 각각에 대해 별도의 거래가 있습니다. 처음 3 개의 커밋과 마지막으로 커밋은 오류로 인해 롤백됩니다.
배치 대 트랜잭션에 대해 약간의 혼동이있을 수 있다고 생각 합니다 .
트랜잭션 중 하나를 성공하거나 하나의 단위로 실패합니다 하나의 명령문이나 명령문 세트입니다. 모든 DDL 문은 트랜잭션 자체에 있습니다 (예 : 100 개의 행을 업데이트하지만 98 행에 오류가 발생하면 행이 업데이트되지 않습니다). 당신은 잘 사용으로 트랜잭션에서 일련의 문을 래핑 할 수 BEGIN TRANSACTION
다음 중 하나 COMMIT
또는 ROLLBACK
.
배치 함께 실행되는 일련의 명령문입니다. 저장 프로시 저는 배치의 예입니다. 저장 프로 시저에서 한 명령문이 실패하고 오류 트래핑 (일반적으로 TRY/CATCH
블록) 이 있으면 후속 명령문이 실행되지 않습니다.
저장된 proc 자체 또는 외부 범위 (이 절차를 호출하는 응용 프로그램 또는 저장된 proc와 같은)에 오류가 발생하여 오류가 발생하면 일괄 처리가 취소되는 문제가 의심됩니다. 이 경우 트래핑하는 모든 범위에서 오류를 처리하는 방법을 조정해야하므로 해결하기가 더 까다 롭습니다.
SQL Server의 모든 것은 트랜잭션에 포함됩니다.
명시 적으로 지정하는 경우 begin transaction
와 end transaction
그것은이라고 명시 적 트랜잭션을 . 당신이하지 않으면, 그것은 암시 적 거래 입니다.
사용중인 모드를 전환하려면
set implicit_transactions on
또는
set implicit_transactions off
select @@OPTIONS & 2
위의 값이 2를 반환하면 암시 적 트랜잭션 모드입니다. 0을 반환하면 자동 커밋에있는 것입니다.
트랜잭션은 데이터베이스를 일관성있는 상태로 유지하기위한 전부 또는 아무것도 아닙니다.
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으로 각 부품을 분리하고 거래가 성공했는지 확인하십시오. 커밋 된 경우 롤백을 수행하십시오. 롤백은 모두 동일한 수준에서 실행되므로 실패한 경우 모두 롤백하지 않고도 각 섹션을 개별적으로 커밋 할 수 있습니다.
자세한 내용은 http://msdn.microsoft.com/en-us/library/ms188929.aspx를 참조하십시오.