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

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

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

在MySql中建立如下表:

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

插入测试数据:

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

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

示例代码:

(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事务一样简单?

基于 Transaction 类的分布式显式事务的更多相关文章

  1. 基于TransactionScope类的分布式隐式事务

    System.Transactions 命名空间中除了上一节中提到的基于 Transaction 类的显式编程模型,还提供使用 TransactionScope 类的隐式编程模型,它与显示编程模型相比 ...

  2. SQLServer之创建显式事务

    显式事务定义 显式事务以 BEGIN TRANSACTION 语句开始,并以 COMMIT 或 ROLLBACK 语句结束. 备注 BEGIN TRANSACTION 使 @@TRANCOUNT 按 ...

  3. (4.19)sql server中的事务模式(隐式事务,显式事务,自动提交事务)

    (4.19)sql server中的事务模式(隐式事务,显式事务,自动提交事务) 1.概念:隐式事务,显式事务,自动提交事务 2.操作:如何设置事务模式 3.存储过程中的事务 XACT_ABORT 1 ...

  4. SQL Server显式事务与隐式事务

    事务是单个的工作单元.如果某一事务成功,则在该事务中进行的所有数据修改均会提交,成为数据库中的永久组成部分.如果事务遇到错误且必须取消或回滚,则所有数据库修改均被清除. SQL Server中有一下几 ...

  5. SpringBoot显式事务

    参考:https://www.jianshu.com/p/f5fc14bde8a0 后续测试代码的完整项目:https://files.cnblogs.com/files/hellohello/dem ...

  6. C++ 不具有继承关系的类之间的显式,隐式转换 2013-07-11 15:41

    好久没有写blog了,今天在学习c#的时候看到某一章节 讲类的隐式与显式转换.特此留笔,以供后续参考之用. 关于显式,隐式转换有些争论,说什么不建议隐式转换.但是个人认为非必要,如果有良好的基础书写基 ...

  7. QT创建与调用Dll方法(包括类成员)--显式调用

    看网上的好多关于QT调用Dll的方法,大部分都是调用函数的,并没有调用C++类成员的情况,即使是有,比如说: 使用Qt编写模块化插件式应用程序 Qt 一步一步实现dll调用(附源码)---(这一篇里没 ...

  8. SQL Server Insert时开启显式事务

    如果没法避免一条一条的写入,那么在处理前显示开启一个事务 begin tran  在处理完成后 commit 这样也要比不开显示事务会快很多! while i < 10000begin inse ...

  9. CALayer的隐式动画和显式动画

    隐式事务 任何对于CALayer属性的修改,都是隐式事务,都会有动画效果.这样的事务会在run-loop中被提交. - (void)viewDidLoad { //初始化一个layer,添加到主视图 ...

随机推荐

  1. ubuntu建立快捷方式

    拷贝一下文件到新的文件里 [Desktop Entry]Categories=Development;Comment[zh_CN]=Comment=Exec=/usr/local/idea-IU-17 ...

  2. oracle数据分组

    一,什么是分组函数 分组函数作用于一组数据,并对一组数据返回一个值 二,分组函数类型 Avg ,count,max,min,stddev(标准方差),sum. 函数名称 函数描述 Count 返回找到 ...

  3. POSTGRESQL 自动登录

    以前习惯使用MYSQL命令行登录,但是到POSTGRESQL不能实现,下面总结一下方法: 1.填写需要链接的postgresql语句,一般放在~/.bash_profile,例如: alias log ...

  4. Spark的运行模式(1)--Local和Standalone

    Spark一共有5种运行模式:Local,Standalone,Yarn-Cluster,Yarn-Client和Mesos. 1. Local Local模式即单机模式,如果在命令语句中不加任何配置 ...

  5. 深入理解JVM内存区域与内存分配

    前言:这是一篇关于JVM内存区域的文章,由网上一些有关这方面的文章和<深入理解Java虚拟机>整理而来,所以会有些类同的地方,也不能保证我自己写的比其他网上的和书本上的要好,也不可能会这样 ...

  6. JSP之include动态包含与静态包含

    转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/6044676.html JSP中,include是一个经常用到的标签.当应用程序中所有的页面的某些部分(如标题. ...

  7. (二)用控制器controller给模型数据赋初始值

    之前博客,非常easy的就实现了模型数据和页面显示的自己主动绑定.如今我们使用控制器,给模型赋初始值. 假设使用jquery来实现变量赋初值,须要在页面载入完毕后运行$("#target&q ...

  8. SpringCloud服务消费者第一次调用出现超时问题的解决方案

    在第一次访问服务消费者的时候(消费者去调用服务提供者服务)会出现如下异常: com.netflix.hystrix.exception.HystrixRuntimeException: TestSer ...

  9. <c:url>标签相关知识点

    <c:url>标签: value:指定路径!他会在路径前面自动添加项目名. <c:url value="/index.jsp"/>,他会输出/day14/i ...

  10. 播布客视频PIT专用播放器MBOO2015

    播布客视频,还是挺不错... 很多视频都是pit后缀的,需要用MBOO2015才可以打开... 00.MB2015软件 01.视频样例 02.download 链接: https://pan.baid ...