संग्रहित प्रक्रिया के लिए लेनदेन का उपयोग न करें


18

मेरे पास एक संग्रहीत प्रक्रिया है जो कुछ कमांड चलाता है। मैं नहीं चाहता कि ये आदेश संग्रहीत प्रक्रिया के लेनदेन में लिपटे रहें। यदि 4 वीं कमांड विफल हो जाती है, तो मैं चाहता हूं कि 1, 2 और 3 वाले रहें और रोलबैक न हो।

क्या संग्रहीत प्रक्रिया को इस तरह से लिखना संभव है कि यह सभी एक बड़े लेनदेन के रूप में निष्पादित न हो?

जवाबों:


16

सभी लेनदेन एक ही लेनदेन में निष्पादित नहीं होंगे। इस उदाहरण पर एक नज़र डालें:

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 कमिट, और आखिरी एक त्रुटि के कारण वापस आती है।


16

मुझे लगता है कि एक बैच बनाम लेनदेन के बारे में यहां कुछ भ्रम हो सकता है ।

एक लेन-देन एक बयान या बयान है कि या तो सफल या एक इकाई के रूप असफल हो जायेगी का सेट है। सभी डीडीएल स्टेटमेंट स्वयं लेन-देन में हैं (यानी यदि आप 100 पंक्तियों को अपडेट करते हैं लेकिन पंक्ति 98 एक त्रुटि फेंकता है, तो कोई भी पंक्तियों को अपडेट नहीं किया जाता है)। आप अच्छी तरह से उपयोग करते हुए के रूप में एक सौदे में बयान की एक श्रृंखला लपेट कर सकते हैं BEGIN TRANSACTIONऔर फिर या तो COMMITया ROLLBACK

एक बैच बयानों की एक श्रृंखला है जिसे एक साथ निष्पादित किया जाता है। एक संग्रहीत प्रक्रिया एक बैच का एक उदाहरण है। एक संग्रहीत कार्यविधि में, यदि कोई कथन विफल हो जाता है और त्रुटि फंसने (सामान्य रूप से TRY/CATCHब्लॉक) हो जाती है, तो बाद के कथन निष्पादित नहीं होंगे।

मुझे संदेह है कि त्रुटि होने पर बैच रद्द हो रहा है क्योंकि या तो संग्रहीत प्रोक स्वयं या बाहरी स्कोप (जैसे अनुप्रयोग या संग्रहीत प्रोक जो इस प्रक्रिया को कॉल करता है) में त्रुटि फंस गई है। यदि ऐसा है तो इसे हल करने के लिए मुश्किल है क्योंकि आपको समायोजित करने की आवश्यकता है कि आप त्रुटियों को जो भी गुंजाइश में फंसा रहे हैं उन्हें कैसे संभालते हैं।


मुझे ऐसा कोई लेख नहीं मिला जो कहता है, "एक स्टोर प्रक्रिया एक बैच का एक उदाहरण है"। मेरा मानना ​​है कि स्टोर की गई प्रक्रिया बैच के समान है लेकिन यह बैच नहीं है। मुख्य अंतर यह है: सपा को आगे संकलित करने और बैच के विपरीत कई बार निष्पादन के लिए तैयार होने की गारंटी है। समानताएं हैं: - वे दोनों एक समय में प्रत्येक कमांड को निष्पादित करते हैं। - यदि एक कमांड विफल हो गई है, तो पिछले सभी कमांड प्रतिबद्ध हैं (जब तक कि यह लेनदेन में नहीं चल रहा था) - यदि एक कमांड विफल हो गई है तो सभी अगले कमांड निष्पादित नहीं किए जाते हैं।
आशी

6

एसक्यूएल सर्वर में सब कुछ एक लेनदेन में निहित है।

जब आप स्पष्ट रूप से निर्दिष्ट करते हैं begin transactionऔर end transactionतब इसे स्पष्ट लेनदेन कहा जाता है । जब आप नहीं करते हैं, तो यह निहित लेनदेन है

आप किस मोड में हैं, इसे बदलने के लिए आप उपयोग करेंगे

set implicit_transactions on

या

set implicit_transactions off

select @@OPTIONS & 2

यदि ऊपर 2 रिटर्न, आप अंतर्निहित लेनदेन मोड में हैं। यदि यह 0 देता है, तो आप ऑटोकॉमिट में हैं।

एक लेन-देन सभी है या डेटाबेस को सुसंगत स्थिति में रखने के लिए कुछ भी नहीं है .. 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'

- अब एसपी बनाएं - ध्यान दें कि पहले 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

इसका संदर्भ लें: क्या हमेशा लेन-देन करना एक बुरा व्यवहार है?


3

यह है कि कैसे संग्रहीत कार्यविधियाँ डिफ़ॉल्ट रूप से काम करती हैं। संग्रहीत प्रक्रिया स्वचालित रूप से किसी लेन-देन के भीतर लिपटी नहीं है।

यदि आप चाहते हैं कि संग्रहित प्रक्रिया बंद हो जाए जब यह पहली त्रुटि से टकराए तो आप उदाहरण के लिए कमांड 2 के साथ समस्या की स्थिति में लौटने के लिए कुछ TRY / CATCH लॉगिन करना चाहेंगे।


2

आपको प्रत्येक कमांड के लिए अलग-अलग लेनदेन की आवश्यकता होगी। आप इसे सहेजे गए लेनदेन के साथ भी पूरा कर सकते हैं:

SAVE TRANSACTION (Transact-SQL)उत्पाद प्रलेखन में देखें ।

मैं चाहता हूं कि व्यक्तिगत लेनदेन इसे संग्रहीत प्रक्रियाओं के लिए डिफ़ॉल्ट व्यवहार करता है, क्योंकि सभी बयान निहित लेनदेन में लिपटे हुए हैं; हालांकि, किसी को भी अपने कोड की नियति को नियंत्रित करने के लिए निहित लेनदेन पर भरोसा नहीं करना चाहिए। यह स्पष्ट रूप से लेन-देन को नियंत्रित करने के तरीके में उत्पादन कोड में नियंत्रित करने के लिए एक बेहतर अभ्यास है।


-2

लेन-देन सफल होने पर प्रत्येक भाग को एक BEGIN TRAN और चेक से अलग करें। यदि वह यह प्रतिबद्ध था, तो एक रोलबैक करें, क्योंकि वे सभी एक ही स्तर से निष्पादित कर रहे हैं, यदि आप असफल होने पर सभी को अलग-अलग रोलबैक किए बिना प्रत्येक अनुभाग को करने में सक्षम होंगे।

अधिक जानकारी के लिए आप यहां देख सकते हैं: http://msdn.microsoft.com/en-us/library/ms188929.aspx


1
क्या यह मेरी संचित प्रक्रिया के भीतर उप लेनदेन का निर्माण करेगा? आदर्श रूप से मैं इससे बचना चाहूंगा कि यदि संभव हो
मैथ्यू स्टील्स

1
यदि किसी लेनदेन के भीतर से एसपी को बुलाया जाता है, तो ऊपर दिए गए सहेजे गए लेन-देन का जवाब है। अगर sp को नहीं बुलाया जाता है, तो @mrdenny सही है। Sql सर्वर नेस्टेड लेनदेन का समर्थन नहीं करता है।
StrayCatDBA

@StrayCatDBA को केवल स्पष्ट करने के लिए .. SQL सर्वर में नेस्टेड लेनदेन हैं, लेकिन वे बुरे हैं .. SQL सर्वर आपको अन्य लेनदेन के अंदर लेनदेन शुरू करने की अनुमति देता है - जिसे नेस्टेड लेनदेन कहा जाता है। का संदर्भ लें sqlskills.com/blogs/paul/... , msdn.microsoft.com/en-us/library/ms189336(v=sql.105).aspx और sqlblog.com/blogs/kalen_delaney/archive/2007/08/13 /…
परिजन शाह

2
स्पष्ट (और आलसी के लिए जो लिंक पर क्लिक नहीं करना चाहते हैं), आप वास्तव में एक और लेनदेन शुरू नहीं कर रहे हैं। पॉल की पोस्ट पर Aka शीर्षक: "मिथक: नेस्टेड लेनदेन असली हैं।" वे असली लेनदेन नहीं हैं। एक नेस्टेड लेन-देन में COMMIT, @@ TRANCOUNT के अलावा कुछ भी नहीं करता है। यह सच है कि यदि आप BEGIN TRAN / COMMIT को घोंसला देते हैं तो आपको कोई त्रुटि नहीं मिलती है, लेकिन यह वास्तविक नेस्टेड संक्रमण होने से अलग है।
स्ट्रायकटीडीबीए
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.