![](/img/trans.png)
[英]Does an Sql server Insert request wait for the Insert Trigger to complete?
[英]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
類型的cmd
的cmd.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.