zoukankan      html  css  js  c++  java
  • 基于 Transaction 类的分布式显式事务

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

  • 相关阅读:
    Character 比较注意先要转换成字符串类型
    ibats注意
    初试体验java多线程
    解压jar
    Velocity语法--转载
    python 批量请求url
    java.lang.NoClassDefFoundError
    疑问
    sql常用语句--转载
    Spring AOP高级——源码实现(3)AopProxy代理对象之JDK动态代理的创建过程
  • 原文地址:https://www.cnblogs.com/hanzhaoxin/p/3751539.html
Copyright © 2011-2022 走看看