C#的事务处理(三层架构)

有一天gemfield去银行给capucivar的账户上转500元,他开始进行操作,相应的sql语句是这样的:”update zhuanzhang set money=money-500 where username=’gemfield’”,此时系统正常运行,执行了该sql语句之后,gemfield账户上的现金少了500元,然后执行 sql语句”update zhanzhang set money=money+500 where username=’capucivar’”,让capucivar账户上的现金增加500元。但是有时候“天不遂人愿”,当gemfield账户上的现金减少了500元之后,还没来得及给capucivar的账户上添加500元数据库突然就断电了。这样的话,gemfield账户上的现金少了500元,但是capucivar账户上的现金却没有多出500元来。这可怎么办,总不能让这500元就凭空消失吧。所以就引出了“事务处理”。

    什么是事务处理?

    可以这样说,每一条语句都独立构成一个事务。在上面的事例中,我们希望两个语句在都执行并没有发生异常之后,再提交结果。那么就将这两个语句组成一个事务。

    接下来要将上面的例子用事务处理的方法做出来,如何写呢?需要注意的是capucivar以前写的Db.cs类即数据处理类,此处与以前所写的不同。下面就来写这个数据处理的类Db.cs:

using System;

using System.Collections.Generic;

using System.Text;

using System.Data;

using System.Data.OleDb;

using System.Collections;

namespace Db//命名空间

{

    public class DbConn

    {

        OleDbConnection conn = null;//声明连接数据库对象

        public DbConn()//构造方法

        {

            if (conn == null)

            {

                conn = new OleDbConnection();//实例化对象

                conn.ConnectionString = "provider=sqloledb.1;data source=.;initial catalog=capucivar;user id=sa;pwd=";//连接数据库

            }

            if (conn.State == ConnectionState.Closed)

            {

                conn.Open();//打开连接

            }

        }

        public DataTable QuerySql(string sql)

        {

            DataTable dt = new DataTable();//实例化一个DataTable对象

            OleDbDataAdapter da = new OleDbDataAdapter(sql, conn);//实例化一个适配器对象

            da.Fill(dt);//将数据填充到DataTable中

            conn_close();//调用conn_close()方法关闭连接

            return dt;//返回结果集

        }

 

        public int Update(ArrayList al)

        {

            OleDbTransaction tran = null;//OleDbTransaction表示要在数据源执行的SQL事物

            tran = conn.BeginTransaction();//BeginTransaction()表示开始数据库事务

            OleDbCommand oc = new OleDbCommand();//OleDbCommand类表示要对数据源执行的 SQL 语句或存储过程。

            oc.Connection = conn;//指定数据库连接

            oc.Transaction = tran;//指定开始的事务

            int x = -1;

 

            try

            {

                foreach (string sql in al)//用foreach遍历ArrayList,ArrayList里的每一个元素都是string类型的sql语句

                {

                    oc.CommandText = sql;//设置要对数据源执行的SQL命令文本

                    x = oc.ExecuteNonQuery();//执行SQL并返回所受影响行数

                                  if(x<=0)//如果x<=0就说明该Sql语句没有成功执行,那么就让它回滚,回滚至没有更新数据之前

                                  { tran.Rollback();//让事物回滚  }

                }

                tran.Commit();//提交事物

            }

            catch//如果发生异常了,就将事务回滚

            {

                x = -1;

                tran.Rollback();//让事物回滚

            }

           conn_close();//调用conn_close()方法关闭数据库连接

            return x;//返回受影响的行数用以判断操作是否成功

        }

        public void conn_close()

        {

            if (conn.State == ConnectionState.Open)

            {

                conn.Close();//关闭连接

            }

        } }

    上面的类写好了,下面来做图形用户界面:

    在写图形用户界面之前,要提到“C#的三层模式”:

    三层模式:

    1、UI:显示层也就是图形用户界面(user interface),它是一个windows窗体应用程序

    2、BLL:业务逻辑层(business logic layer)。它是一个类库,在该层里经常是些sql语句的和封装字段的。封装字段的代码经常写在一个VO文件夹下 VO是value object的所写。

    3、DAL:数据访问层(data access layer)。同样是类库。该层就是连接数据库,和执行sql语句的。

使用三层模式要注意:这三层是毫无联系的三个项目,如何让它们联系起来?首先重新生成DAL层--à将DAL层添加引用到BLL层--àBLL层重新生成--à将BLL层添加引用到UI层,这样就会将三个毫无联系的三个项目通过添加引用联系起来。

    三层模式也就这些了,下面该来写上面例子的BLL层了,BLL层下有一个文件夹叫VO,在该文件夹下写一个类:

using System;

using System.Collections.Generic;

using System.Text;

namespace Bll.VO//命名空间

{

    public class Person

    {

//下面是将字段封装通过get和set来取值或赋值

        private string yourname = string.Empty;//自己的名字

        public string Yourname

        {

            get { return yourname; }

            set { yourname = value; }

        }

        private string yourhao = string.Empty//自己的帐号;

        public string Yourhao

        {

            get { return yourhao; }

            set { yourhao = value; }

        }

        private string hishao = string.Empty;//对方的帐号

        public string Hishao

        {

            get { return hishao; }

            set { hishao = value; }

        }

        private int money = -1;//一个用户的现金

        public int Money

        {

            get { return money; }

            set { money = value; }

        } } }

封装成一个类之后,来写业务逻辑层:

using System;

using System.Collections.Generic;

using System.Text;

using System.Collections;

using System.Data;

namespace Bll//命名空间

{

    public class Sql

    {

 

        public bool exeSql(VO.Person ps)

        {

            string sql1 = string.Format("update zhuanzhang set money=money-{0} where zhanghao='{1}'",ps.Money,ps.Yourhao);

            string sql2 = string.Format("update zhuanzhang set money=money+{0} where zhanghao='{1}'", ps.Money, ps.Hishao);//拼写Sql语句

            ArrayList al = new ArrayList();//ArrayList对象al

            al.Add(sql1);

            al.Add(sql2)//为ArrayList添加值;

            int x = new Db.DbConn().Update(al);//执行Db.DbConn().Update()放法之后将返回的受影响行数赋给x

            if (x > 0)//判断x,如果x大于0那么就执行成功,返回true,否则的话返回false

                return true;

            return false;

        }

//下面是查询所有信息,将信息显示出来,以方便观察执行是否成功       

public DataTable select()

        {

            string sql = "select username,zhanghao,money from zhuanzhang";//拼写sql语句

          return new Db.DbConn().QuerySql(sql);//返回查询结果

        }

    }

}

最后就剩下UI层了:

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Text;

using System.Windows.Forms;

namespace zhuanzhang

{

    public partial class Form1 : Form

    {

        public Form1()

        {

            InitializeComponent();

        }

//下面是点击按钮后发生

        private void submit_but_Click(object sender, EventArgs e)

        {

//首先分别得到文本框里的值

            string yName = name_text.Text;

            string yNum = zhanghao_text.Text;

            string hNum = hishao_text.Text;

            int money = Convert.ToInt32(money_text.Text);

//将上面的字段通过Bll.VO.Person进行封装

            Bll.VO.Person ps = new Bll.VO.Person();

            ps.Yourname = yName;

            ps.Yourhao = yNum;

            ps.Hishao = hNum;

            ps.Money = money;

            bool b = new Bll.Sql().exeSql(ps);//通过返回值判断转账是否成功

            if (b)

            {

                MessageBox.Show("转账成功!");

            }

            else

            {

                MessageBox.Show("转账失败!");

            }

            refurbish();//调用refurbish()方法将下面表格中的数据从数据库中重新查找一次再显示出来

        }

        private void Form1_Load(object sender, EventArgs e)

        {

            refurbish();

        }

        public void refurbish()

        {

            DataTable dt = new Bll.Sql().select();//得到结果集

            this.dataGridView1.DataSource = dt;//将dataGridView1的数据源指定为dt

        }

    }

}

    事务处理使用“三层模式”写完了,可以来看看结果:

    先输入一个错误的对方帐号,显示“转账失败”,点击“确定”之后,可以看到数据库中的数据并没有改变。

   

 

    输入正确的:它显示“转账成功”的对话框,点击“确定”之后,可以发现“现金”这一列中的现金数已经改变了。

 

    上面的结果正是我们想要的。

    对于上面capucivar提到的“三层模式”,建议大家以后经常使用。因为使用三层模式会增强代码的逻辑性,并且使你的思路很清楚。也许刚开始不会觉着这些好处,那是因为手生,练习的多了,就会非常熟练的掌握它了。

posted on 2009-09-02 13:50  欣路历程  阅读(8267)  评论(0编辑  收藏  举报

导航