在上一篇,咱們寫了簡單的Hello world微服務,如今,咱們往這個微服務當中,加入一個支持分佈式事務的函數,由於不想寫太長的代碼,我就不用數據庫作演示了,只是簡單給你們演示一下,怎麼把事務的提交、回滾,放到一個委託當中。html
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 MicroServiceTransaction CreateMST() { var logger = ServiceProvider.GetService<ILogger<MicroServiceTransaction>>(); return new MicroServiceTransaction("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 屬性,這樣也能起到事務委託的效果,代碼以下:api
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 AfterAction(string actionName, object[] parameters) { base.AfterAction(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全部函數,設置分佈式事務委託。分佈式
系統處理優先級:ide
當函數中第一個參數爲TransactionDelegate類型,而且裏面的委託不爲空,那麼,事務由這個參數進行處理。函數
若是函數中沒有定義TransactionDelegate參數,而this.TransactionControl不爲空,並且委託也不爲空,那麼,事務由 this.TransactionControl 進行處理。
微服務
using ( var tran = CreateMST() ) { var api = tran.GetMicroService<HelloWorldApi>(); //異步調用AddUser api.AddUserAsync("Jack1");
//同步調用AddUser
api.AddUser("Jack2"); tran.Commit();//自動等待全部異步調用完成,並提交全部事務 }
經過JMSClient.SupportTransaction屬性,可控制調用的服務,不受強一致性事務的控制。ui
using ( var tran = CreateMST() ) { var api = tran.GetMicroService<HelloWorldApi>(); //異步調用AddUser api.AddUserAsync("Jack1"); api.AddUser("Jack2"); tran.SupportTransaction = false;//使後面調用的服務,不參與事務的強一致性 api.AddUser("Jack3"); tran.Commit();//自動等待全部異步調用完成,並提交全部事務 }