基于 Transaction 类的分布式显式事务

本文涉及的产品
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
云数据库 RDS MySQL Serverless,价值2615元额度,1个月
简介:

自.NET2.0以来增加了System.Transactions命名空间,为.NET应用程序带来了一个新的事务编程模型。

这个命名空间提供了几个依赖的TransactionXXX类。Transaction是所有事务处理类的基类,并且定义了所有事务类都可以使用的属性、方法和事件。CommittableTransaction是唯一个支持提交的事务类,这个类有一个Commit()方法,所有其他事务类都只能执行回滚。

本文将通过银行转账的示例介绍基于 Transaction 类的分布式显式事务的用法。

在MySql中建立如下表:

image

注意Balance是无符号的decimal类型(如下图)

image

插入测试数据:

(转账成功的测试数据):

image

(转账失败的测试数据):

image

示例代码:

(1)SqlHelper.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Configuration;
using MySql.Data.MySqlClient;
using System.Transactions;
using System.Data;
 
namespace 事务处理
{
    public class SqlHelper
    {
        public static string GetConnection()
        {
            string connStr = ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
            return connStr;
        }
        public static int ExecuteNonQuery(Transaction transaction,string sql,params MySqlParameter[] parameters)
        {
            int result = -1;
            using (MySqlConnection conn = new MySqlConnection(GetConnection()))
            {
                conn.Open();
                if (null != transaction)
                {
                    conn.EnlistTransaction(transaction);    //将连接登记到事务
                }
                using (MySqlCommand cmd = conn.CreateCommand())
                {
                    cmd.CommandText = sql;
                    cmd.Parameters.AddRange(parameters);
                    result = cmd.ExecuteNonQuery();
                }
            }
            return result;
        }
 
        public static DataTable ExecuteDataTable(string sql, params MySqlParameter[] parameters)
        {
            using (MySqlConnection conn = new MySqlConnection(GetConnection()))
            {
                using (MySqlCommand cmd = conn.CreateCommand())
                {
                    cmd.CommandText = sql;
                    cmd.Parameters.AddRange(parameters);
                    using (MySqlDataAdapter da = new MySqlDataAdapter(cmd))
                    {
                        using (DataSet ds = new DataSet())
                        {
                            da.Fill(ds);
                            return ds.Tables[0];
                        }
                    }
                }
            }
        }
    }
 
}

(2)Bankaccountn.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using MySql.Data.MySqlClient;
using System.Data;
using System.Transactions;
 
namespace 事务处理
{
    public class Bankaccountn
    {
        public Bankaccountn(string bankaccountnId)
        {
            string sql = @"SELECT * FROM Bankaccountn WHERE BankaccountnId=@BankaccountnId;";
            DataTable dt = SqlHelper.ExecuteDataTable(sql, new MySqlParameter("@BankaccountnId", bankaccountnId));
            if (dt.Rows.Count <= 0)
            {
                throw new Exception("账户不存在!");
            }
            else if (dt.Rows.Count > 1)
            {
                throw new Exception("异常信息:有重名的账户存在!");
            }
            else
            {
                this.bankaccountnId = dt.Rows[0]["BankaccountnId"] as string;
                this.UserName = dt.Rows[0]["UserName"] as string;
                this.Balance = Convert.ToDecimal(dt.Rows[0]["Balance"]);
            } 
        }
 
        private string bankaccountnId;
        public string UserName
        { 
            get; 
            private set; 
        }
        public decimal Balance
        {
            get;
            private set;
        }
        protected int Update(Transaction transaction)
        {
            string sql = @"UPDATE bankaccountn SET UserName = @UserName,Balance = @Balance 
                           WHERE BankaccountnId= @BankaccountnId;";
            return SqlHelper.ExecuteNonQuery(transaction, sql, new MySqlParameter("@BankaccountnId", this.bankaccountnId), new MySqlParameter("@UserName", this.UserName), new MySqlParameter("@Balance", this.Balance));
 
        }
        #region 支出 + Epend(Transaction transaction, decimal money)
        public void Epend(Transaction transaction, decimal money)
        {
            this.Balance -= money;
            this.Update(transaction);
        }
        #endregion
 
        #region 收入 + Income(Transaction transaction, decimal money)
        public void Income(Transaction transaction, decimal money)
        {
            this.Balance += money;
            this.Update(transaction);
        }
        #endregion
 
        public bool TransferOfAccount(string incomeBankaccountnId, decimal money)
        {
            using (var transaction = new CommittableTransaction())
            {
                try
                {
                    Bankaccountn incomeBankaccountn = new Bankaccountn(incomeBankaccountnId);
                    incomeBankaccountn.Income(transaction, money); //收款账户入账
                    this.Epend(transaction, money); //付款账户支出
                    transaction.Commit();
                    return true;
                }
                catch 
                {
                    transaction.Rollback();
                    //这里写做异常信息的记录的代码
                    return false; 
                }
            }
        }
    }
    
}

(3)测试代码

Bankaccountn one = new Bankaccountn("6666660123456789");
           if (one.TransferOfAccount("6666669876543210", 200M))
           {
               Response.Write("<script>alert('转账成功')</script>");
           }
           else
           {
               Response.Write("<script>alert('转账失败')</script>");
           }

代码分析:

创建基于 Transaction 类的分布式显式事务步骤如下:

1)实例化一个可提交的CommittableTransaction对象;

2)将要参与事务的连接通过MySqlConnection对象的EnlistTransaction(Transaction transaction)登记到上一步创建的CommittableTransaction对象上;

3)如果事务可以成功完成,使用CommittableTransaction对象的Commit()方法提交事务处理结果;

4)如果事务处理中发生错误,就调用CommittableTransaction对象的Rollback()方法,撤销每一个修改。


这样分析下来是不是和上一节的ADO.NET事务一样简单?

作者: 韩兆新
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
分类:  [06]ASP.NET相关
标签:  ASP.NET

本文转自韩兆新博客博客园博客,原文链接:http://www.cnblogs.com/hanzhaoxin/p/3751539.html,如需转载请自行联系原作者
相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
4月前
|
运维 监控 Java
Spring Cloud Alibaba分布式事务问题之事务commit失败如何解决
Spring Cloud Alibaba提供了一套在Spring Cloud框架基础上构建的微服务解决方案,旨在简化分布式系统的开发和管理;本合集将探讨Spring Cloud Alibaba在实际应用中的部署和使用技巧,以及该框架常见问题的诊断方法和解决步骤。
|
3月前
|
消息中间件 Dubbo 应用服务中间件
分布式事物【Hmily实现TCC分布式事务、Hmily实现TCC事务、最终一致性分布式事务解决方案】(七)-全面详解(学习总结---从入门到深化)
分布式事物【Hmily实现TCC分布式事务、Hmily实现TCC事务、最终一致性分布式事务解决方案】(七)-全面详解(学习总结---从入门到深化)
86 0
|
Dubbo 应用服务中间件 微服务
分布式事物【Hmily实现TCC分布式事务、Hmily实现TCC事务、最终一致性分布式事务解决方案】(七)-全面详解(学习总结---从入门到深化)(上)
分布式事物【Hmily实现TCC分布式事务、Hmily实现TCC事务、最终一致性分布式事务解决方案】(七)-全面详解(学习总结---从入门到深化)
51 1
|
7天前
|
消息中间件 Java 关系型数据库
Spring事务与分布式事务
这篇文档介绍了事务的概念和数据库事务的ACID特性:原子性、一致性、隔离性和持久性。在并发环境下,事务可能出现更新丢失、脏读和不可重复读等问题,这些问题通过设置事务隔离级别(如读未提交、读已提交、可重复读和序列化)来解决。Spring事务传播行为有七种模式,影响嵌套事务的执行方式。`@Transactional`注解用于管理事务,其属性包括传播行为、隔离级别、超时和只读等。最后提到了分布式事务,分为跨库和跨服务两种情况,跨服务的分布式事务通常通过最终一致性策略,如消息队列实现。
|
3月前
|
消息中间件 RocketMQ Docker
分布式事物【RocketMQ事务消息、Docker安装 RocketMQ、实现订单微服务、订单微服务业务层实现】(八)-全面详解(学习总结---从入门到深化)
分布式事物【RocketMQ事务消息、Docker安装 RocketMQ、实现订单微服务、订单微服务业务层实现】(八)-全面详解(学习总结---从入门到深化)
54 0
|
4月前
|
消息中间件 RocketMQ 微服务
分布式事物【Hmily实现TCC分布式事务、Hmily实现TCC事务、最终一致性分布式事务解决方案】(七)-全面详解(学习总结---从入门到深化)(下)
分布式事物【Hmily实现TCC分布式事务、Hmily实现TCC事务、最终一致性分布式事务解决方案】(七)-全面详解(学习总结---从入门到深化)
59 1
|
4月前
|
消息中间件 RocketMQ Docker
分布式事物【RocketMQ事务消息、Docker安装 RocketMQ、实现订单微服务、订单微服务业务层实现】(八)-全面详解(学习总结---从入门到深化)(下)
分布式事物【RocketMQ事务消息、Docker安装 RocketMQ、实现订单微服务、订单微服务业务层实现】(八)-全面详解(学习总结---从入门到深化)
30 0
|
消息中间件 RocketMQ Docker
分布式事物【RocketMQ事务消息、Docker安装 RocketMQ、实现订单微服务、订单微服务业务层实现】(八)-全面详解(学习总结---从入门到深化)(上)
分布式事物【RocketMQ事务消息、Docker安装 RocketMQ、实现订单微服务、订单微服务业务层实现】(八)-全面详解(学习总结---从入门到深化)
71 0
|
4月前
|
存储 消息中间件 关系型数据库
解密分布式事务:CAP理论、BASE理论、两阶段提交(2PC)、三阶段提交(3PC)、补偿事务(TCC)、MQ事务消息、最大努力通知
解密分布式事务:CAP理论、BASE理论、两阶段提交(2PC)、三阶段提交(3PC)、补偿事务(TCC)、MQ事务消息、最大努力通知
|
6月前
|
缓存 NoSQL Redis
分布式系列教程(04) -分布式Redis缓存 (事务&主从复制&哨兵机制)
分布式系列教程(04) -分布式Redis缓存 (事务&主从复制&哨兵机制)
104 0