उत्तर के लिए थोड़ा देर हो चुकी है :) लेकिन आशा है कि यह दूसरों के लिए उपयोगी होगा। उत्तर में तीन भाग होते हैं:
- इसका क्या अर्थ है "किसी अन्य सत्र में लेन-देन प्रसंग का उपयोग किया जा रहा है।"
- त्रुटि कैसे पुन:उत्पन्न करें "किसी अन्य सत्र द्वारा उपयोग में लेन-देन प्रसंग।"
<मजबूत>1. इसका क्या अर्थ है "किसी अन्य सत्र में लेन-देन प्रसंग का उपयोग किया जा रहा है।"
महत्वपूर्ण सूचना:लेन-देन संदर्भ लॉक को SqlConnection
. के बीच बातचीत के ठीक पहले और तुरंत बाद जारी किया जाता है और एसक्यूएल सर्वर।
जब आप कुछ SQL क्वेरी निष्पादित करते हैं, SqlConnection
"दिखता है" क्या इसे लपेटने वाला कोई लेनदेन है। यह SqlTransaction
हो सकता है (एसक्यूएलकनेक्शन के लिए "मूल") या Transaction
System.Transactions
. से सभा।
जब लेन-देन पाया गया SqlConnection
SQL सर्वर के साथ संचार करने के लिए इसका उपयोग करता है और फिलहाल वे Transaction
communicate प्रसंग विशेष रूप से बंद है।
TransactionScope
क्या करता है? ? यह Transaction
बनाता है और इसके बारे में .NET Framework Components जानकारी प्रदान करता है, इसलिए SqlConnection सहित हर कोई (और डिज़ाइन द्वारा) इसका उपयोग कर सकता है।
तो TransactionScope
घोषित करना हम नया लेनदेन बना रहे हैं जो वर्तमान Thread
में तत्काल सभी "लेन-देन योग्य" वस्तुओं के लिए उपलब्ध है ।
वर्णित त्रुटि का अर्थ निम्न है:
- हमने कई
SqlConnections
बनाए हैं उसी के अंतर्गतTransactionContext
(जिसका अर्थ है कि वे एक ही लेन-देन से संबंधित हैं) - हमने ये
SqlConnection
के बारे में पूछा SQL सर्वर के साथ एक साथ संचार करने के लिए - उनमें से एक ने मौजूदा
Transaction
को लॉक कर दिया है संदर्भ और अगली एक फेंकी गई त्रुटि
<मजबूत>2. त्रुटि कैसे पुन:उत्पन्न करें "किसी अन्य सत्र द्वारा उपयोग में लेन-देन प्रसंग।"
सबसे पहले, लेन-देन के संदर्भ का उपयोग ("लॉक") sql कमांड निष्पादन के समय किया जाता है। इसलिए निश्चित रूप से इस तरह के व्यवहार को पुन:पेश करना मुश्किल है।
लेकिन हम एकल लेनदेन के तहत अपेक्षाकृत लंबे SQL संचालन चलाने वाले कई थ्रेड शुरू करके इसे करने का प्रयास कर सकते हैं। आइए तालिका तैयार करें [dbo].[Persons]
[tests]
. में डेटाबेस:
USE [tests]
GO
DROP TABLE [dbo].[Persons]
GO
CREATE TABLE [dbo].[Persons](
[Id] [bigint] IDENTITY(1,1) NOT NULL PRIMARY KEY,
[Name] [nvarchar](1024) NOT NULL,
[Nick] [nvarchar](1024) NOT NULL,
[Email] [nvarchar](1024) NOT NULL)
GO
DECLARE @Counter INT
SET @Counter = 500
WHILE (@Counter > 0) BEGIN
INSERT [dbo].[Persons] ([Name], [Nick], [Email])
VALUES ('Sheev Palpatine', 'DarthSidious', '[email protected]')
SET @Counter = @Counter - 1
END
GO
और "किसी अन्य सत्र द्वारा उपयोग में लेन-देन संदर्भ" को पुन:पेश करें। श्रीके कोड उदाहरण के आधार पर C# कोड में त्रुटि
using System;
using System.Collections.Generic;
using System.Threading;
using System.Transactions;
using System.Data.SqlClient;
namespace SO.SQL.Transactions
{
public static class TxContextInUseRepro
{
const int Iterations = 100;
const int ThreadCount = 10;
const int MaxThreadSleep = 50;
const string ConnectionString = "Initial Catalog=tests;Data Source=.;" +
"User ID=testUser;PWD=Qwerty12;";
static readonly Random Rnd = new Random();
public static void Main()
{
var txOptions = new TransactionOptions();
txOptions.IsolationLevel = IsolationLevel.ReadCommitted;
using (var ctx = new TransactionScope(
TransactionScopeOption.Required, txOptions))
{
var current = Transaction.Current;
DependentTransaction dtx = current.DependentClone(
DependentCloneOption.BlockCommitUntilComplete);
for (int i = 0; i < Iterations; i++)
{
// make the transaction distributed
using (SqlConnection con1 = new SqlConnection(ConnectionString))
using (SqlConnection con2 = new SqlConnection(ConnectionString))
{
con1.Open();
con2.Open();
}
var threads = new List<Thread>();
for (int j = 0; j < ThreadCount; j++)
{
Thread t1 = new Thread(o => WorkCallback(dtx));
threads.Add(t1);
t1.Start();
}
for (int j = 0; j < ThreadCount; j++)
threads[j].Join();
}
dtx.Complete();
ctx.Complete();
}
}
private static void WorkCallback(DependentTransaction dtx)
{
using (var txScope1 = new TransactionScope(dtx))
{
using (SqlConnection con2 = new SqlConnection(ConnectionString))
{
Thread.Sleep(Rnd.Next(MaxThreadSleep));
con2.Open();
using (var cmd = new SqlCommand("SELECT * FROM [dbo].[Persons]", con2))
using (cmd.ExecuteReader()) { } // simply recieve data
}
txScope1.Complete();
}
}
}
}
और अंत में आपके आवेदन में लेनदेन समर्थन को लागू करने के बारे में कुछ शब्द:
- यदि संभव हो तो बहु-थ्रेडेड डेटा संचालन से बचें (चाहे लोड हो रहा हो या सहेजा जा रहा हो)। उदा. सहेजें
SELECT
/UPDATE
/ etc... एक ही कतार में अनुरोध करता है और एकल-थ्रेड कार्यकर्ता के साथ उनकी सेवा करता है; - मल्टी-थ्रेडेड एप्लिकेशन में लेनदेन का उपयोग करते हैं। हमेशा। हर जगह। पढ़ने के लिए भी;
- एक से अधिक थ्रेड के बीच एकल लेनदेन साझा न करें। यह अजीब, स्पष्ट, अनुवांशिक और प्रतिलिपि प्रस्तुत करने योग्य नहीं . का कारण बनता है त्रुटि संदेश:
- "किसी अन्य सत्र द्वारा उपयोग में लेन-देन प्रसंग।":एक लेन-देन के तहत सर्वर के साथ एक साथ कई इंटरैक्शन;
- "टाइमआउट समाप्त हो गया है। ऑपरेशन पूरा होने से पहले समय समाप्त हो गया है या सर्वर प्रतिक्रिया नहीं दे रहा है।":निर्भर लेनदेन पूरा नहीं हुआ;
- "लेन-देन संदेह में है";
- ... और मैं बहुत कुछ मानता हूं ...
TransactionScope
. के लिए आइसोलेशन लेवल सेट करना न भूलें . डिफ़ॉल्टSerializable
है लेकिन ज्यादातर मामलों मेंReadCommitted
काफी है;- पूर्ण करना न भूलें()
TransactionScope
औरDependentTransaction