C#回顾学习笔记四十一:在三层架构中使用事务

1)为什么要特别强调如何在三层架构中处理事务?
在讲解这个之前,先要熟悉三层架构是什么(UI层、BLL层、DAL层)。如果还不了解三层架构的话,可以先阅读前一篇文章:http://blog.csdn.net/privatehiroki/article/details/78120598
在三层架构中,如果要同时对两个sql语句进行操作,比如需要增加两个用户的信息,而且保证必须成功,通常的做法是连续调用两次已写好的方法,比如自定义的Add()方法,功能是增加一条记录。但是 要实现事务处理,首先保证在同一个数据库链接中
先做一个练习,来还原一下上面说的没有事务时如何添加两条记录。
第1步,使用SQLserver创建数据库,名字叫CRUDTest。新建表,名字叫Student。如图所示:
C#回顾学习笔记四十一:在三层架构中使用事务_第1张图片
第2步,新建类库文件(DAL层),名字叫Student.DAL。在DAL层下新建SqlHelper类和StudentDAL类,代码分别如下。
SqlHelper类代码:
class SqlHelper
    {
        private static readonly string connStr = ConfigurationManager.ConnectionStrings["testConn"].ConnectionString;
        public static SqlConnection createConnection()
        {
            SqlConnection conn = new SqlConnection(connStr);
            conn.Open();
            return conn;
        }
        //执行操作:增、删、改
        public static int ExecuteNoneQuery(SqlConnection conn, string sql, params SqlParameter[] parameters)
        {
            using (SqlCommand cmd = conn.CreateCommand())
            {
                cmd.CommandText = sql;
                cmd.Parameters.AddRange(parameters);//添加SqlParameters数组
                return cmd.ExecuteNonQuery();//返回
            }
        }
        public static int ExecuteNoneQuery(string sql, params SqlParameter[] parameters)
        {
            using (SqlConnection conn = createConnection())
            {
                return ExecuteNoneQuery(conn, sql, parameters);
            }
        }
    }

StudentDAL类代码:
public class StudentDAL
    {
        public int Add(string Name, string Birthday, string Gender, int? Tall, int? Weight, string Address)
        {
            object obj = SqlHelper.ExecuteScalar("insert into Student values(@Name,@Birthday,@Gender,@Tall,@Weight,@Address)",
                new SqlParameter("@Name", Name),
                new SqlParameter("@Birthday", Birthday),
                new SqlParameter("@Gender", Gender),
                new SqlParameter("@Tall", Tall == null ? (object)DBNull.Value : Tall),
                new SqlParameter("@Weight", Weight ?? (object)DBNull.Value),
                new SqlParameter("@Address", Address == null ? (object)DBNull.Value : Address));
            return Convert.ToInt32(obj);
        }
    }
第3步,新建类库文件(BLL层),名字叫Student.BLL。添加对Student.DAL的引用,然后新建StudentBLL类,详细代码如下(注意要using Student.DAL;):
public class StudentBLL
    {
        private StudentDAL sDal = new StudentDAL();
        public int Add(string Name, string Birthday, string Gender, int? Tall, int? Weight, string Address)
        {
            return sDal.Add(Name, Birthday, Gender, Tall, Weight, Address);
        }
    }
第4步,新建窗体应用程序(UI层),名字叫Student.Winform。添加对Student.BLL的引用,然后添加一个Button按钮控件,并注册一个单击事件,后台代码如下(注意要using Student.BLL;):
public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        private void button1_Click(object sender, EventArgs e)
        {
            StudentBLL bll = new StudentBLL();
            int num = bll.Add("stu6", "2014-12-25", "男", 120, 100, "北京市中关村");
            int num2 = bll.Add("stu7", "2017-10-12", "男", 130, 110, "中石油小区");
        }
    }
第5步,在窗体应用程序的App.config中标签下配置数据库连接字符串,代码如下:

   
 

第6步,将窗体应用程序设为启动项并运行程序。现在要来完成一个测试:通过单击按钮就可以连续在数据库写入两条记录。如果上面代码无问题,则运行后并单击按钮,数据库会成功写入两条记录。

2)对于上面的练习,如果在增加两条记录的中途出现了异常会怎样

现在对上面代码做一些修改,使得第一句sql执行成功后就出现异常,故意让第二句sql无法得到执行。在按钮单击事件里添加如下图所示的一句代码:

C#回顾学习笔记四十一:在三层架构中使用事务_第2张图片
如上图所示,添加这句代码后,程序会在执行成功第一句sql后抛出异常并中断程序的继续执行。

3)在三层架构中使用事务
第1步,给Student.Winform窗体应用程序添加引用System.Transactions。
第2步,在窗体应用程序中using System.Transactions;,然后修改按钮单击事件的代码如下:
private void button1_Click(object sender, EventArgs e)
        {
            StudentBLL bll = new StudentBLL();
            using (TransactionScope tx = new TransactionScope())//事务处理
            {
                int num = bll.Add("stu9", "2014-12-25", "男", 120, 100, "北京市中关村");
                Convert.ToInt32("abc");//人为地制造一个异常
                int num2 = bll.Add("stu10", "2017-10-12", "男", 130, 110, "中石油小区");
                tx.Complete();
            }
        }
第3步,将sql操作包裹到TransactionScope中,这样就可以被事务所监控。当其中出现异常时,让所有修改过的数据回滚到修改之前。

4)TransactionScope的补充
1.在运行程序后,程序会检测是否存在TransactionScope的对象,如果存在,则将其中的所有操作登记到TransactionScope中,这样就受其控制。

2.如何看待“事务不是属于DAL层的吗,为什么放到UI层处理?”这个问题。实际上,架构只是为了更好解决问题而存在,并不是约束程序员。如果某些方式更加方便,那么违反三层架构也是可以的。


你可能感兴趣的:(C#学习回顾笔记)