AOD.NET实现数据库事物Transaction

在开始介绍文章主要内容前先简单说一下事务

1.事务介绍

  事务是一种机制、是一种操作序列,它包含了一组数据库操作命令,这组命令要么全部执行,要么全部不执行。因此事务是一个不可分割的工作逻辑单元。在数据库系统上执行并发操作时事务是作为最小的控制单元来使用的。这特别适用于多用户同时操作的数据通信系统。

2.事务使用场景

  需要对数据库同时进行多条更新操作时!例如,电商平台的下单付款,银行转账之类的


 

  好了,这里就不对事物进行细说了,想了解更多与事务有关的详细知识可以去园子里搜索哈

  执行事务的步骤

  1.连接数据库,连接数据库后会返回一个SqlConnection对象,我这里在数据库连接后将其赋值给了一个全局的SqlConnection对象——_con

  2.用返回的SqlConnection对象用BeginTransaction()方法生产并开始一个事务对象。

  3.执行所有对数据库进行更改操作的Sql语句。

   在对数据库进行更改时需要用到SqlCommand,在用生成SqlCommand对象后必须给其绑定事务(Transaction),不绑定会报错。

     在这里需要注意的是所有SqlCommand对象绑定的SqlConnection必须是同一个SqlConection对象,所有SqlCommand对象绑定的事务对象必须是同一个事务对象。若没绑定相同的SqlConnection对象和SqlTransaction,事务便会如同虚设。

  4.所有Sql语句执行成功后SqlTransaction对象可使用Commit()方法提交事务,失败则用Rollback()回滚事务,将数据库回滚到第一天sql执行前的状态。

  5.关闭数据库连接,释放资源。

  话不多说搬Code,注释代码上都有,如有不明白的地方或是有更好的意见请在下方留言区留下你的评论

事务方法

public static int ModifyDatabaseTran(List<string> SqlStrList, List<SqlParameter[]> SqlParList) {
            int result = 0;
            //打开数据库连接
            SqlConnection con = OpenDatabase();
            //_con:全局SqlConnection对象
            //生成事物对象
            SqlTransaction tran = _con.BeginTransaction();
            try
            {
                //遍历并执行SqlStrList集合里面的Sql语句
                for (int i = 0; i < SqlStrList.Count; i++)
                {
                    //将Sql语句与其对应的SqlParameter[]绑定并生成SqlCommand对象
                    SqlCommand com = BulidCommand(SqlStrList[i], SqlParList[i]);
                    //给SqlCommand对象绑定事务,必须绑定同一个事务对象否则跑不出事务效果
                    com.Transaction = tran;
                    //返回受影响的行数
                    result = com.ExecuteNonQuery();                   
                }
                //若最后执行的sql是插入语句result的值便=0,这里将其值改为1告诉调用者sql语句执行成功
                if (result == 0) result = 1;
                //所有Sql语句执行成功后提交事务
                tran.Commit();

            }
            catch (Exception)
            {
                //SqlStrList集合里面有一条Sql语句执行失败便执行事务回滚操作,回滚后报错Sql语句之前执行的Sql语句都将无效
                //同时数据库恢复SqlStrList集合里面的Sql语句执行前的状态
          result=0; tran.Rollback(); } finally { //关闭数据库连接,释放资源 if (_con != null && _con.State != ConnectionState.Closed) { _con.Close(); con.Dispose(); } tran.Dispose(); } //返回结果 0:失败,1:成功 return result; }

打开数据库连接的方法

//数据库连接字符串
        private const string conStr = "server=.;database=Food;uid=sa;pwd=123456";

        private static SqlConnection _con;

        /// <summary>
        /// 打开数据库连接
        /// </summary>
        /// <returns></returns>
        private static SqlConnection OpenDatabase() {
            if (_con == null || _con.State == ConnectionState.Closed)
            {
                _con = new SqlConnection(conStr);
                _con.Open();
            }
            return _con;
        }

生产SqlCommand对象方法

/// <summary>
        /// 参数化查询绑定参数
        /// </summary>
        /// <param name="sqlStr"></param>
        /// <param name="SqlPar"></param>
        /// <returns></returns>
        private static SqlCommand BulidCommand(string sqlStr,SqlParameter[] SqlPar) {
            SqlConnection con = OpenDatabase();
            SqlCommand com = new SqlCommand(sqlStr, con);
            com.Parameters.AddRange(SqlPar);
            return com;
        }

 

实例

下面例子本来是想用winform写个注册,结界觉着拖控件太麻烦了,索性就直接在代码里面写sql了

页面(输入框可以自动忽略,这里只用到了按钮的点击事件)

执行操作前的member表状态

注册按钮点击事件代码(页面控件是从登陆页面复制过来的注册按钮的Name属性没有更改所以事件名称是LoginBtn_Click而不是RegisterBtn_Click)

private void LoginBtn_Click(object sender, EventArgs e)
        {
            List<string> sqlStr = new List<string>
            {
                { @"insert member values(@MemberAccount,@Password)"},
                { @"insert member values(@MemberAccount,@Password)"}
            };
            List<SqlParameter[]> sqlPar = new List<SqlParameter[]>
            {
                new SqlParameter[] { new SqlParameter("@MemberAccount","lei1"), new SqlParameter("@Password", "123456") },
                new SqlParameter[] { new SqlParameter("@MemberAccount","lei2"), new SqlParameter("@Password", "123456") }
            };

            int result=DBHlep.ModifyDatabaseTran(sqlStr,sqlPar);
            if (result > 0)
            {
                MessageBox.Show("成功!");
            }
            else {
                MessageBox.Show("失败!");
            }
        }

点击注册按钮后我们再来看看member表状态

上面的是Sql语句不报错的执行结果,接下来,我们将第二条sql语句的表名从menber改为menber1,看看member表的数据会发生什么变化

PS:我的数据库里面没有表member1所以第二条sql必定会执行失败,第二条sql失败后我们看看表member是否新增了一条数据(第一条sql是正确的,只修改了第二条sql的表名),新增了一条数据则事务执行失败,反之事务执行成功

private void LoginBtn_Click(object sender, EventArgs e)
        {
            List<string> sqlStr = new List<string>
            {
                { @"insert member values(@MemberAccount,@Password)"},
                //将第二条sql的表名修改为member1
                { @"insert member1 values(@MemberAccount,@Password)"}
            };
            List<SqlParameter[]> sqlPar = new List<SqlParameter[]>
            {
                new SqlParameter[] { new SqlParameter("@MemberAccount","lei1"), new SqlParameter("@Password", "123456") },
                new SqlParameter[] { new SqlParameter("@MemberAccount","lei2"), new SqlParameter("@Password", "123456") }
            };

            int result=DBHlep.ModifyDatabaseTran(sqlStr,sqlPar);
            if (result > 0)
            {
                MessageBox.Show("成功!");
            }
            else {
                MessageBox.Show("失败!");
            }
        }

点击注册按钮后看表member的数据是否发生了变化

member表数据未发生变化,事务执行成功!

好了,这篇博客到这里就结束了,如有不明白之处或是有更好的意见请在下方留言区留下你的评论

posted @ 2018-12-02 17:44  小点心♀  阅读(378)  评论(0编辑  收藏  举报