在上一篇,我們寫了簡單的Hello world微服務,現在,我們往這個微服務當中,加入一個支持分布式事務的函數,因為不想寫太長的代碼,我就不用數據庫做演示了,只是簡單給大家演示一下,怎么把事務的提交、回滾,放到一個委托當中。
using System; using System.Collections.Generic; using System.Text; using JMS; using Microsoft.Extensions.Logging; namespace MyHelloworldService { class HelloworldController : MicroServiceControllerBase { static List<string> Users = new List<string>(); ILogger<HelloworldController> _logger; public HelloworldController(ILogger<HelloworldController> logger) { _logger = logger; } /// <summary> /// 哈嘍方法 /// </summary> /// <param name="time">我當前的時間</param> /// <returns>中文問候語</returns> public string Hello(DateTime time) { return $"你好,你給的時間是: {time.ToShortDateString()}"; } /// <summary> /// 添加用戶 /// </summary> /// <param name="tranDelegate">當第一個參數為TransactionDelegate類型,表示這是一個事務委托</param> /// <param name="username">用戶名</param> /// <returns>是否添加成功</returns> public bool AddUser(TransactionDelegate tranDelegate , string username) { if (Users.Contains(username)) return false; //把提交放到委托 tranDelegate.CommitAction = () => { _logger.LogInformation("提交事務成功"); }; //把回滾放到委托 tranDelegate.RollbackAction = () => { lock (Users) { Users.Remove(username); } _logger.LogInformation("回滾事務成功"); }; lock (Users) { Users.Add(username); } return true; } /// <summary> /// 獲取所有用戶名 /// </summary> /// <returns></returns> public string[] GetAllUsers() { return Users.ToArray(); } } }
AddUser函數,由於第一個參數是TransactionDelegate類型,所以這個函數支持分布式事務,把事務的提交與回滾,托管給這個變量即可。
客戶端同樣預先調用這段代碼,重新生成一次HelloWorld.cs:
using ( var tran = CreateMST() ) { var api = tran.GetMicroService("Hello world"); var code = api.GetServiceClassCode("TestApplication" , "HelloWorldApi"); File.WriteAllText("../../../HelloWorldApi.cs", code, Encoding.UTF8); }
調用端代碼改為這樣:
using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using System; using System.IO; using System.Text; using System.Threading; using Way.Lib; namespace TestApplication { class Program { static IServiceProvider ServiceProvider; static RemoteClient CreateMST() { var logger = ServiceProvider.GetService<ILogger<RemoteClient>>(); return new RemoteClient("192.168.40.131", 7900, null, logger); } static void Main(string[] args) { Thread.Sleep(3000);//等服務啟動完畢 ServiceCollection services = new ServiceCollection(); services.AddLogging(loggingBuilder => { loggingBuilder.SetMinimumLevel(LogLevel.Debug); loggingBuilder.AddConsole(); }); ServiceProvider = services.BuildServiceProvider(); using ( var tran = CreateMST() ) {
tran.SetHeader("auth" , "abc");//自定義header信息
var api = tran.GetMicroService<HelloWorldApi>(); var ret = api.Hello(DateTime.Now); Console.WriteLine(ret); api.AddUser("Jack1"); api.AddUser("Jack2"); var allusers = api.GetAllUsers(); Console.WriteLine("回滾前用戶列表:{0}" , allusers.ToJsonString()); tran.Rollback();//回滾所有事務 allusers = api.GetAllUsers(); Console.WriteLine("回滾后用戶列表:{0}", allusers.ToJsonString()); } } } }
跑一下工程,效果如下:

方法二
上面,為了實現事務,方法的第一個參數,必須是TransactionDelegate類型,這樣,如果每個方法都要支持事務,那么,很可能每個方法都要寫一遍相同的委托代碼,這樣就有點繁瑣,
如果委托的代碼都一樣,我們可以實例化 this.TransactionControl 屬性,這樣也能起到事務委托的效果,代碼如下:
using System; using System.Collections.Generic; using System.Text; using JMS; using Microsoft.Extensions.Logging; using Org.BouncyCastle.Bcpg; namespace MyHelloworldService { class HelloworldController : MicroServiceControllerBase { DBContext _db; ILogger<HelloworldController> _logger; public HelloworldController(ILogger<HelloworldController> logger) { _logger = logger; } public override void OnAfterAction(string actionName, object[] parameters) { base.OnAfterAction(actionName, parameters); if(_db != null) { this.TransactionControl = new TransactionDelegate(this.TransactionId); this.TransactionControl.CommitAction = () => { _db.CommitTransaction(); }; this.TransactionControl.RollbackAction = () => { _db.RollbackTransaction(); }; } } /// <summary> /// 添加用戶 /// </summary> /// <param name="username">用戶名</param> /// <returns>是否添加成功</returns> public bool AddUser(string username) { _db = new DBContext(); _db.Insert(new User { Name = username }); return true; } /// <summary> /// 獲取所有用戶名 /// </summary> /// <returns></returns> public string[] GetAllUsers() { return _db.Users.ToArray(); } } }
這是數據庫事務的大概例子,在Controller里面,定義 DBContext 局部變量 _db,然后在AfterAction里,把_db事務的提交、回滾,交給 this.TransactionControl 。
this.TransactionControl 是用來針對整個Controller所有函數,設置分布式事務委托。
系統處理優先級:
當函數中第一個參數為TransactionDelegate類型,並且里面的委托不為空,那么,事務由這個參數進行處理。
如果函數中沒有定義TransactionDelegate參數,而this.TransactionControl不為空,而且委托也不為空,那么,事務由 this.TransactionControl 進行處理。
客戶端異步調用微服務
using ( var tran = CreateMST() ) {
tran.BeginTransaction(); var api = tran.GetMicroService<HelloWorldApi>(); //異步調用AddUser api.AddUserAsync("Jack1");
//同步調用AddUser
api.AddUser("Jack2"); tran.Commit();//自動等待所有異步調用完成,並提交所有事務 }
