zoukankan      html  css  js  c++  java
  • JMS微服务开发示例(二)编写分布式事务

    在上一篇,我们写了简单的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 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 属性,这样也能起到事务委托的效果,代码如下:

    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() )
                {
                    var api = tran.GetMicroService<HelloWorldApi>();                 
    
                    //异步调用AddUser
                    api.AddUserAsync("Jack1");
    
    //同步调用AddUser
    api.AddUser("Jack2"); tran.Commit();
    //自动等待所有异步调用完成,并提交所有事务 }

     客户端控制某个服务不参与强一致性事务

    通过JMSClient.SupportTransaction属性,可控制调用的服务,不受强一致性事务的控制。

                using ( var tran = CreateMST() )
                {
                    var api = tran.GetMicroService<HelloWorldApi>();                 
    
                    //异步调用AddUser
                    api.AddUserAsync("Jack1");
                    api.AddUser("Jack2");
    
    
                    tran.SupportTransaction = false;//使后面调用的服务,不参与事务的强一致性
                    api.AddUser("Jack3");
    
                    tran.Commit();//自动等待所有异步调用完成,并提交所有事务
    
                }

    上一篇 示例(一)     下一篇 示例(三)分布式锁

  • 相关阅读:
    HTTP报文详解
    常用的HTTP协议
    URL详解
    一起切磋
    emacs使用指南
    SSH自动部署
    linux上应用随机启动
    让Maven正确处理javac警告
    最近的学习
    Java application 性能分析分享
  • 原文地址:https://www.cnblogs.com/IWings/p/13356794.html
Copyright © 2011-2022 走看看