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();//自动等待所有异步调用完成,并提交所有事务
    
                }

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

  • 相关阅读:
    10. Regular Expression Matching
    9. Palindrome Number
    6. ZigZag Conversion
    5. Longest Palindromic Substring
    4. Median of Two Sorted Arrays
    3. Longest Substring Without Repeating Characters
    2. Add Two Numbers
    链式表的按序号查找
    可持久化线段树——区间更新hdu4348
    主席树——树链上第k大spoj COT
  • 原文地址:https://www.cnblogs.com/IWings/p/13356794.html
Copyright © 2011-2022 走看看