您的位置:首页 > 运维架构 > 网站架构

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

2009-09-02 13:50 537 查看
有一天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提到的“三层模式”,建议大家以后经常使用。因为使用三层模式会增强代码的逻辑性,并且使你的思路很清楚。也许刚开始不会觉着这些好处,那是因为手生,练习的多了,就会非常熟练的掌握它了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: