在專案需要進行 SQL 分散式交易的時候,使用 TransactionScope 是一個不錯的選擇。
要使用 TransactionScope 進行分散式交易,除了程式碼之外,環境也要作相對應的設定,可參考小弟文章:【Windows】啟用 MSDTC 服務與相關設定。
1、情境設計
有兩個位於不同資料庫主機的資料庫,其中都有一個名為【Student】的資料表,資料結構完全相同,Id 為主索引。
希望有個 Move 的方法,傳入 StudentId 時,將此筆 Student 資料由來源資料庫複製至目標資料庫,並刪除來源資料庫的 Student 資料,最後回傳搬移結果。
2、TransactionScope 實作
在命名空間 System.Transactions 下的 TransactionScope 類別,是 .NET 用來包覆交易式程式碼區塊的類別。
在 TransactionScope 範圍內的資料庫操作均會受到交易保護。若範圍內只針對單一資料庫進行操作,則與使用 ADO.NET 一樣;若範圍內針對多個不同資料庫進行操作,則會被提升成為分散式交易。
底下程式碼使用 Nuget 套件:Dapper 進行實作。
using Dapper;
using Model;
using System.Data.SqlClient;
using System.Linq;
using System.Transactions;
namespace Service
{
public sealed class TransactionService
{
private readonly string sourceConnectionString;
private readonly string targetConnectionString;
public TransactionService(string sourceConnectionString, string targetConnectionString)
{
this.sourceConnectionString = sourceConnectionString;
this.targetConnectionString = targetConnectionString;
}
public bool MoveStudent(int studentId)
{
try
{
using (var scope = new TransactionScope())
{
var student = new Student();
using (var sqlConn = new SqlConnection(this.sourceConnectionString))
{
var students = sqlConn.Query<Student>(@"SELECT [Id], [Name] FROM [Student] WHERE [Id] = @Id", new { Id = studentId });
if (students == null || students.Count() != 1)
{
return false;
}
student = students.Single();
sqlConn.Execute(@"DELETE FROM [Student] WHERE [Id] = @Id AND [Name] = @Name", student);
}
using (var sqlConn = new SqlConnection(this.targetConnectionString))
{
sqlConn.Execute(@"INSERT INTO [Student]([Id], [Name]) VALUES (@Id, @Name)", student);
}
// 若在 complete 前發生例外,包含在 scope 內的交易將會被 roll back
scope.Complete();
return true;
}
}
catch
{
return false;
}
}
}
}
- :Source Code
- MSDN:TransactionScope
- Microsoft Doc:System.Transactions Integration with SQL Server
嘗試將自己的理解寫成文字紀錄,資料來源均來自於網路。
如有理解錯誤、引用錯誤或侵權,請多加指正與告知,讓我有更多的進步與改進的空間,謝謝!