JMS微服務開發示例(二)編寫分佈式事務

在上一篇,咱們寫了簡單的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();//自動等待全部異步調用完成,並提交全部事務

            }

 

上一篇 示例(一)     下一篇 示例(三)分佈式鎖this

相關文章
相關標籤/搜索