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

时间:2023-02-03 16:41:55

System.Transactions 命名空间中除了上一节中提到的基于 Transaction 类的显式编程模型,还提供使用 TransactionScope 类的隐式编程模型,它与显示编程模型相比,更加方便简单,它也是MSDN中建议使用的编程模型。

下面,我们基于TransactionScope类实现上一节银行转帐的例程。

示例代码:

(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(string sql, params MySqlParameter[] parameters)

        {

            int result = -1;

            using (MySqlConnection conn = new MySqlConnection(GetConnection()))

            {

                conn.Open();

                

                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()

        {

            string sql = @"UPDATE bankaccountn SET UserName = @UserName,Balance = @Balance 

                           WHERE BankaccountnId= @BankaccountnId;";

            return SqlHelper.ExecuteNonQuery(sql, new MySqlParameter("@BankaccountnId", this.bankaccountnId), new MySqlParameter("@UserName", this.UserName), new MySqlParameter("@Balance", this.Balance));

 

        }

        public void Epend( decimal money)

        {

            this.Balance -= money;

            this.Update();

        }

        public void Income(decimal money)

        {

            this.Balance += money;

            this.Update();

            

        }

        public bool HiddenTransferOfAccount(string incomeBankaccountnId, decimal money)

        {

            bool result = true;

            using (TransactionScope scope = new TransactionScope())

            {

                try

                {

                    Bankaccountn incomeBankaccountn = new Bankaccountn(incomeBankaccountnId);

                    incomeBankaccountn.Income(money); //收款账户入账

                    this.Epend(money); //付款账户支出

                    scope.Complete();

                }

                catch (Exception ex)

                {

                    //这里写做异常信息的记录的代码

                    result = false;

                }

            }

            return result;

        }

    }

    

}

(3)测试代码

Bankaccountn one = new Bankaccountn("6666660123456789");

if (one.HiddenTransferOfAccount("6666669876543210", 200M))

{

    Response.Write("<script>alert('转账成功')</script>");

}

else

{

    Response.Write("<script>alert('转账失败')</script>");

}

代码分析:

使用TransactionScope 之后,事务管理器会 预执行代码,直至Complete()处,如果过程没有出错,这通知事务管理器去提交,如果错误就不提交,保证了整个执行过程的一致性。

但,在使用隐式编程模型时应注意以下几点:

1)要确保参与事务的资源(如连接的打开等)的全登记放在TransactionScope 实例化对象之后,调用Complete()方法之前。

2)从TransactionScope 实例化到调用Complete()方法之间的代码,不要吃掉异常。

 

 

using (TransactionScope scope = new TransactionScope())

{

    try

    {

        //要确保参与事务的资源全部登记在这个位置(如连接的打开等)

         Bankaccountn incomeBankaccountn = new Bankaccountn(incomeBankaccountnId);

         incomeBankaccountn.Income(money); //收款账户入账

         this.Epend(money); //付款账户支出

         scope.Complete();

    }

    catch (Exception ex)

    {

         //捕获异常要在这个位置

          result = false;

    }

}