Không sử dụng giao dịch cho Thủ tục lưu trữ


18

Tôi có một thủ tục được lưu trữ chạy một vài lệnh. Tôi không muốn các lệnh này được gói trong giao dịch của thủ tục được lưu trữ. Nếu lệnh thứ 4 thất bại, tôi muốn các lệnh thứ 1, 2 và 3 ở lại và không quay lại.

Có thể viết thủ tục được lưu trữ theo cách mà tất cả không thực hiện như một giao dịch lớn không?

Câu trả lời:


16

Tất cả các giao dịch sẽ không thực hiện trong một giao dịch. Hãy xem ví dụ này:

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;

Đây là đầu ra:

nhập mô tả hình ảnh ở đây

Bằng cách tạo phiên Sự kiện mở rộng để theo dõi sql_transactionsự kiện, đây là đầu ra từ việc thực thi dbo.ChangeValues:

nhập mô tả hình ảnh ở đây

Như bạn có thể thấy trong ảnh chụp màn hình ở trên, có các giao dịch riêng biệt cho mỗi trong bốn câu lệnh. 3 cam kết đầu tiên và lần cuối cùng quay lại vì lỗi.


16

Tôi nghĩ rằng có thể có một số nhầm lẫn ở đây về một so với một giao dịch .

Một giao dịch là một tuyên bố hoặc tập hợp các báo cáo rằng một trong hai sẽ thành công hay thất bại như một đơn vị. Tất cả các câu lệnh DDL đều nằm trong chính các giao dịch (nghĩa là nếu bạn cập nhật 100 hàng nhưng hàng 98 sẽ xuất hiện lỗi, không có hàng nào được cập nhật). Bạn có thể gói một loạt các báo cáo trong một giao dịch bằng cách sử dụng BEGIN TRANSACTIONvà sau đó COMMIThoặc ROLLBACK.

Một là một chuỗi các câu lệnh được thực thi cùng nhau. Một thủ tục được lưu trữ là một ví dụ về một lô. Trong một thủ tục được lưu trữ, nếu một câu lệnh thất bại và có lỗi bẫy (thường là TRY/CATCHcác khối) thì các câu lệnh tiếp theo sẽ không thực thi.

Tôi nghi ngờ vấn đề của bạn là lô đang bị hủy khi xảy ra lỗi vì chính Proc được lưu trữ hoặc phạm vi bên ngoài (như ứng dụng hoặc Proc được lưu trữ gọi thủ tục này) có lỗi trong đó. Nếu đó là trường hợp khó giải quyết hơn vì bạn cần điều chỉnh cách bạn xử lý lỗi ở bất kỳ phạm vi nào đang bẫy chúng.


Tôi không tìm thấy bất kỳ bài viết nào có nội dung: "Thủ tục lưu trữ là một ví dụ về một lô". Tôi tin rằng Thủ tục lưu trữ rất giống với lô nhưng nó không phải là một lô. Sự khác biệt chính là: SP được đảm bảo được biên dịch trước và sẵn sàng thực hiện nhiều lần không giống như Batches. Điểm giống nhau là: - Cả hai đều thực thi từng lệnh một. - Nếu một lệnh thất bại thì tất cả các lệnh trước đó được cam kết (trừ khi nó đang chạy trong một giao dịch) - nếu một lệnh bị lỗi thì tất cả các lệnh tiếp theo sẽ không được thực thi.
Ashi

6

Tất cả mọi thứ trong máy chủ sql được chứa trong một giao dịch.

Khi bạn chỉ định rõ ràng begin transactionend transactionsau đó nó được gọi là Giao dịch rõ ràng . Khi bạn không, thì đó là giao dịch ngầm .

Để chuyển chế độ bạn đang sử dụng, bạn sẽ sử dụng

set implicit_transactions on

hoặc là

set implicit_transactions off

select @@OPTIONS & 2

nếu ở trên trả về 2, bạn đang ở chế độ giao dịch ngầm. Nếu nó trả về 0, bạn đang ở chế độ tự động.

Một giao dịch là TẤT CẢ hoặc không có gì để giữ cơ sở dữ liệu ở trạng thái nhất quán .. hãy nhớ các thuộc tính 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'

- tạo SP ngay bây giờ - lưu ý rằng 3 đầu tiên sẽ thành công và thứ 4 sẽ thất bại do cắt chuỗi ...

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

Tham khảo: Có phải là một thực tế xấu khi luôn tạo ra một giao dịch?


3

Đây là cách các thủ tục lưu trữ hoạt động theo mặc định. Thủ tục lưu trữ không được bao bọc trong một giao dịch tự động.

Nếu bạn muốn thủ tục được lưu trữ dừng lại khi nó gặp lỗi đầu tiên, bạn sẽ muốn đăng nhập TRY / CATCH vào đó để quay lại trong trường hợp xảy ra sự cố với lệnh 2 chẳng hạn.


2

Bạn sẽ cần các giao dịch riêng lẻ cho mỗi lệnh. Bạn cũng có thể thực hiện điều này với các giao dịch đã lưu:

Xem SAVE TRANSACTION (Transact-SQL)trong tài liệu sản phẩm.

Tôi muốn đủ điều kiện giao dịch cá nhân đó là hành vi mặc định cho các thủ tục được lưu trữ, bởi vì tất cả các câu lệnh được gói trong các giao dịch ngầm; tuy nhiên, không ai nên dựa vào các giao dịch ngầm để kiểm soát số phận của mã của họ. Đó là một thực tiễn tốt hơn nhiều để kiểm soát rõ ràng cách xử lý các giao dịch trong mã sản xuất.


-2

tách riêng từng bộ phận bằng BEGIN TRẦN và kiểm tra xem giao dịch có thành công hay không. nếu nó đã được cam kết, nếu không thì thực hiện khôi phục, vì tất cả chúng đều thực thi từ cùng cấp, bạn sẽ có thể cam kết từng phần riêng biệt mà không phải quay lại tất cả nếu thất bại.

Để biết thêm thông tin, bạn có thể xem tại: http://msdn.microsoft.com/en-us/l Library / ms188929.aspx


1
Điều đó sẽ tạo ra các giao dịch phụ trong Thủ tục lưu trữ của tôi chứ? Lý tưởng nhất là tôi muốn tránh điều đó nếu có thể
Matthew Steeples

1
Nếu SP được gọi từ trong một giao dịch, thì các giao dịch đã lưu ở trên là câu trả lời. Nếu sp không được gọi với, thì @mrdenny là chính xác. Máy chủ Sql không hỗ trợ giao dịch lồng nhau.
StrayCatDBA

@StrayCatDBA chỉ để làm rõ .. có các Giao dịch lồng nhau trong SQL Server, nhưng chúng là ác .. SQL Server cho phép bạn bắt đầu giao dịch bên trong các giao dịch khác - được gọi là giao dịch lồng nhau. Tham khảo sqlskills.com/blogs/paul/... , msdn.microsoft.com/en-us/library/ms189336(v=sql.105).aspxsqlblog.com/blogs/kalen_delaney/archive/2007/08/13 /
Lọ

2
Để rõ ràng (và đối với những người lười biếng không muốn nhấp vào liên kết), bạn không thực sự bắt đầu một giao dịch khác. Aka tiêu đề trên bài đăng của Paul: "Huyền thoại: Giao dịch lồng nhau là có thật." Họ không giao dịch thực sự. CAM KẾT trong một giao dịch lồng nhau không làm gì khác ngoài việc giảm @@ TRANCOUNT. Đúng là bạn không gặp lỗi nếu bạn lồng BẮT ĐẦU TRAN / CAM KẾT, nhưng điều đó khác với việc chuyển đổi lồng nhau thực sự.
StrayCatDBA
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.