Sqlserver
 sql >> Teknologi Basis Data >  >> RDS >> Sqlserver

Apa alasan konteks Transaksi digunakan oleh sesi lain?

Agak terlambat menjawabnya :) tapi semoga bermanfaat bagi orang lain. Jawaban terdiri dari tiga bagian:

  1. Apa artinya "Konteks transaksi sedang digunakan oleh sesi lain".
  2. Cara mereproduksi kesalahan "Konteks transaksi sedang digunakan oleh sesi lain."

1. Apa artinya "Konteks transaksi sedang digunakan oleh sesi lain".

Pemberitahuan penting:Kunci konteks transaksi diperoleh sebelum dan segera dirilis setelah interaksi antara SqlConnection dan SQLServer.

Saat Anda menjalankan beberapa SQL Query, SqlConnection "terlihat" apakah ada transaksi yang membungkusnya. Mungkin SqlTransaction ("asli" untuk SqlConnection) atau Transaction dari System.Transactions perakitan.

Saat transaksi ditemukan SqlConnection menggunakannya untuk berkomunikasi dengan SQL Server dan saat ini mereka berkomunikasi Transaction konteks dikunci secara eksklusif.

Apa yang dimaksud dengan TransactionScope ? Itu menciptakan Transaction dan memberikan informasi .NET Framework Components tentangnya, sehingga semua orang termasuk SqlConnection dapat (dan sesuai desain) menggunakannya.

Jadi mendeklarasikan TransactionScope kami membuat Transaksi baru yang tersedia untuk semua objek "yang dapat ditransaksikan" yang dibuat dalam Thread saat ini .

Kesalahan yang dijelaskan berarti sebagai berikut:

  1. Kami membuat beberapa SqlConnections di bawah TransactionContext yang sama (yang berarti mereka terkait dengan transaksi yang sama)
  2. Kami menanyakan SqlConnection ini untuk berkomunikasi dengan SQL Server secara bersamaan
  3. Salah satunya mengunci Transaction current konteks dan kesalahan berikutnya

2. Cara mereproduksi kesalahan "Konteks transaksi sedang digunakan oleh sesi lain."

Pertama-tama, konteks transaksi digunakan ("dikunci") tepat pada saat eksekusi perintah sql. Jadi pasti sulit untuk mereproduksi perilaku seperti itu.

Tetapi kita dapat mencoba melakukannya dengan memulai beberapa utas yang menjalankan operasi SQL yang relatif lama di bawah satu transaksi. Mari kita siapkan tabel [dbo].[Persons] di [tests] Basis Data:

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

Dan mereproduksi "Konteks transaksi sedang digunakan oleh sesi lain." kesalahan dengan kode C# berdasarkan contoh kode Shrike

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();
            }
        }
    }
}

Dan sebagai kesimpulan, beberapa kata tentang penerapan dukungan transaksi di aplikasi Anda:

  • Hindari operasi data multi-utas jika memungkinkan (tidak masalah memuat atau menyimpan). Misalnya. simpan SELECT /UPDATE / etc... permintaan dalam satu antrean dan melayaninya dengan pekerja utas tunggal;
  • Dalam aplikasi multi-utas gunakan transaksi. Selalu. Di mana pun. Bahkan untuk membaca;
  • Jangan bagikan satu transaksi di antara banyak utas. Itu menyebabkan aneh, tidak jelas, transendental dan tidak dapat direproduksi pesan kesalahan:
    • "Konteks transaksi sedang digunakan oleh sesi lain.":beberapa interaksi simultan dengan server dalam satu transaksi;
    • "Waktu habis kedaluwarsa. Jangka waktu habis sebelum operasi selesai atau server tidak merespons.":transaksi tidak tergantung selesai;
    • "Transaksi diragukan.";
    • ... dan saya berasumsi banyak lainnya ...
  • Jangan lupa set Isolation Level untuk TransactionScope . Standarnya adalah Serializable tetapi dalam kebanyakan kasus ReadCommitted cukup;
  • Jangan lupa untuk Complete() TransactionScope dan DependentTransaction


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Menggunakan Suka pada Variabel Parameter?

  2. Lima Pertimbangan Teratas untuk Desain Indeks Basis Data di SQL Server

  3. Bagaimana menerapkan Memiliki Klausa dengan Grup dengan di Select Query - Tutorial SQL Server / TSQL Bagian 131

  4. 3 Cara Mengekstrak Bulan dari Tanggal di SQL Server (T-SQL)

  5. Kapan saya bisa meng-host IIS dan SQL Server di mesin yang sama?