一次提交涉及两个数据库处理

业务场景:用户下单à付款à扣减库存

问题:当付款成功,扣减库存失败,如何处理。是否可以将这两个事务放在一个Transaction中处理?

   

   

 

一、基本概念(Transaction)

什么是事务?事务很任性,只接受成功或失败。在事务包括的范围内,所有操作都是不可分割的单元,当所有操作都成功后事务才算执行成功,否则将进行回滚操作。回忆一下课本中的ACID四大属性(了解即可,复制了书中的描述):

A(Atomicity)原子性:不可再分割的整体,事务中的含义是所有操作都被视为同一不可分割的整体,要么都成功要么都失败。

C(Consistence)一致性:事务开始前和事务结束后,数据库的完整性约束没有被破坏。

I(Isolation)隔离性:当数据正处于事务中时是独占的,不能被其它应用所访问,确保不会读取到脏数据。

D(Durability)持久性:事务一旦提交,则物理存储于数据库中,且在下一次操作前,数据的状态不会被改变。

 

二、解决方案

通过System.TransactionScope 可以实现两个库之间的事务,我们只需要引入System.Transactions.dll 就可以微软提供的强大事务功能了。这里实现的是两个数据库之间的整务,若是要实现数据库和NTFS文件之间的事务,请大家搜索DTC机制,来实现非数据库之间的事务。这部分内容我也正在实践和学习,待理解以后再发出博文与大家探讨。

本实例是连接了本机的两个数据库服务SQLServer2008R2和MySQL,所以需要在工程中引入MySQL.dll。

 以下是实现代码,当DoPayment方法执行成功后,Dostock方法执行失败,此时事务不执行transcope.Complete();语句,在SQLServer中的数据会被回滚。并且在执行Dostock方法时,去查询SQLServer中是查询不到数据的。

namespace ConsoleApplication3
{
    class Program
    {
        static string SQLConStr = "server=10.10.60.195,1433;database=tmp;uid=sa;pwd=sa;";
        static string MySQLConStr = "server=localhost;uid=root;pwd=root;database=test";
        static void Main(string[] args)
        {
            OrderLogic();
        }

        public static void OrderLogic()
        {
            using (TransactionScope transcope = new TransactionScope())
            {
                //用户付款
                //向SQLServer.TPayment表插入一条记录
                string sqlText = "insert into TPayment values(156,1,1)";
                DoPayment(sqlText);

                //扣减库存
                //更新MySQL.Product表中stocknum字段
                string mysqlText = "update Product set stocknum=stocknum-5 where id=1";
                DoStock(mysqlText);

                transcope.Complete();
            }
        }

        public static void DoPayment(string sqlText)
        {
            SqlConnection conn = null;
            SqlCommand com = null;

            try
            {
                conn = new SqlConnection(SQLConStr);
                conn.Open();

                com = new SqlCommand(sqlText, conn);
                com.ExecuteNonQuery();
            }
            catch
            {

            }
            finally
            {
                if (com != null)
                    com.Dispose();
                if (conn != null)
                    conn.Close();
            }
        }

        public static void DoStock(string sqlText)
        {
            MySqlConnection conn = null;
            MySqlCommand com = null;

            try
            {
                conn = new MySqlConnection(MySQLConStr);
                conn.Open();

                com = new MySqlCommand(sqlText, conn);
                com.ExecuteNonQuery();
            }
            catch
            {

            }
            finally
            {
                if (com != null)
                    com.Dispose();
                if (conn != null)
                    conn.Close();
            }
        }
    }
}

 

posted @ 2015-03-25 13:34  Set sail  阅读(335)  评论(0编辑  收藏  举报