簡體   English   中英

如何等待SQL Server數據庫回滾完成?

[英]How to wait for a SQL Server database rollback to complete?

使用ADO.NET SqlClient類時,可以通過幾種方式回滾事務。 通過顯式調用SqlTransaction.Rollback ,或者在事務范圍內具有命令超時或事務超時等。

但是,如何在使用SQL Server(2012或更高版本)時檢測此回滾何時完成? 對於長時間運行的事務,回滾可能需要很長時間,並且它通常在數據庫上非常密集,因此立即重試事務可能不明智。 在我們的情況下,我們希望等待回滾完成。

(在我們的特定情況下,由於使用TransactionScope類的事務超時而發生回滾,但我更喜歡一種適用於任何類型的回滾的方法)。

我查看了最初看起來很有希望的sys.dm_exec_requests 它的命令類型最初為KILL/ROLLBACK ,並報告進度百分比。 (如果我從原始事務中捕獲了SPID,我將能夠輪詢該表並等待它完成)。 但是,大約一半時間我注意到它改為AWAITING COMMAND (而回滾仍然在執行)。

我還看了KILL <SPID> WITH STATUSONLY 如果沒有正在進行的回滾,這似乎會產生錯誤,因此它可以用於輪詢方法,但我注意到如果我從SSMS運行BEGIN TRAN ... ROLLBACK TRAN批處理,則報告錯誤說當它回滾時沒有回滾正在進行中。 在這種情況下, dm_exec_requests表將ROLLBACK TRANSACTION報告為命令類型。

那么如何才能以可靠的方式等待回滾呢?

您可以根據spid查看sp_who的事務活動。 status將告訴您當前的事務狀態以及完成時從rollback或消除更改的更改。

如果您想獲得有關.NET的反饋,請使用SqlChangeMonitor示例 )緩存結果並等待SqlChangeMonitor通知rollback更改。


如果您修復了超時問題,可以查看:

使用IsolationLevel.ReadCommitted 這樣您的.NET代碼將等待Commit或Rollback的完成。

(它看起來像帶有SqlCommand類型的cmdcmd.Connection.BeginTransaction(IsolationLevel.ReadCommitted)

SqlRollback.cs 

using System;
using System.Data.SqlClient;
using System.Threading;

namespace Events
{
    public class SqlRollback
    {
        private string _connString = "Server=(localdb)\\mssqllocaldb;Database=QueryIt.EmployeeDb;Trusted_Connection=true";
        public event EventHandler TransactionRolledBack;

        public void Transact()
        {
            using (SqlConnection conn = new SqlConnection(_connString))
            {
                conn.Open();

                var command = conn.CreateCommand();
                SqlTransaction transaction;
                transaction = conn.BeginTransaction("Transaction");

                command.Connection = conn;
                command.Transaction = transaction;

                try
                {
                    transaction.Save("checkpoint");
                    command.CommandText = "INSERT INTO Employees (name, discriminator) VALUES ('Dimitar', 'Bastun')";
                    command.ExecuteNonQuery();
                    throw new Exception();

                } catch (Exception ex)
                {
                    transaction.Rollback("checkpoint"); //Rolling back to the checkpoint
                    Thread.Sleep(5000); //Simulating some time
                    transaction.Commit();
                    this.OnTransactionRollingBack(EventArgs.Empty);
                }
            }
        }

        private void OnTransactionRollingBack(EventArgs e)
        {
            EventHandler handler = TransactionRolledBack;
            if(handler != null)
            {
                handler(this, EventArgs.Empty);
            }
        }
    }
}

Program.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Events
{
    class Program
    {
        static void Main(string[] args)
        {
            var rollBack = new SqlRollback();
            rollBack.TransactionRolledBack += RollBack_TransactionRolledBack;

            try
            {
                rollBack.Transact();
            } catch (Exception e)
            {

            }
        }

        private static void RollBack_TransactionRolledBack(object sender, EventArgs e)
        {
            Console.WriteLine("Rooled!");
        }
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM