机房收费系统中的事务(二)

在前一段时间,我写过一篇在机房收费系统使用事务的一篇博客,下面是链接地址

http://blog.csdn.net/yjjm1990/article/details/7347853

守宏师兄(http://blog.csdn.net/lsh6688)仔细看过之后,给出了自己的观点,并且指出了代码中的不足处。下面我将细细道来,希望对博友有些帮助,并希望大家提出宝贵意见!

首先要说的是SQLHelper这个数据库助手类,在我的原文中,处理事务的方法是和执行非查询语句一起执行的。其实可以感觉到,这里就有了代码的“坏味道”,我们都知道职责单一原则。职责单一原则是对类而言的,而类又是由方法组成的,那么一个方法当然也应该做到职责单一。而在第一篇博文中的SQLHelper类里的ExecuteNonQuery其实就拥有两个功能,一个是执行含有事务的SQL;另一个是执行不含事务的SQL。这个判断是放在了SQLHelper类里,其实一个比较好的处理方法是把这个方法分成两个方法,一个是执行含有事务的SQL语句或存储过程,一个是执行不含有事务的SQL语句或存储过程。

那么判断要怎么处理呢?

最好是放在D层去处理。

下面是一个方法清晰,功能完善的数据库助手类SQLHelper

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Collections;

using System.Configuration;


namespace SqlHelp
{
    public class SqlHelper
    {
        private string strCon;


        private SqlConnection SqlCon;//定义连接
        private SqlDataReader sDr;//定义dataReader
        private SqlCommand sCmd;//定义Commond
        /// <summary>
        /// xml中连接字符串
        /// </summary>
        /// <param name="connName"></param>
        public SqlHelper(string connName)
        {

            strCon = ConfigurationManager.ConnectionStrings[connName].ConnectionString;

        }

        /// <summary>
        /// 执行sql语句(事务中)
        /// </summary>
        /// <param name="cmdText">在事务中执行的某个Sql语句或者存储过程</param>
        /// <param name="paras">参数</param>
        /// <param name="CmdType">类型</param>
        /// <param name="sqlconn">连接</param>
        /// <param name="sqlTran">事务</param>
        /// <returns>返回受影响的行数</returns>
        public int ExecNoSelect(string cmdText, SqlParameter[] paras, CommandType CmdType, SqlConnection sqlconn, SqlTransaction sqlTran)
        {
            sCmd = new SqlCommand(cmdText, sqlconn);
            sCmd.CommandType = CmdType;
            sCmd.Parameters.AddRange(paras);
            sCmd.Transaction = sqlTran;

            return sCmd.ExecuteNonQuery();


        }









        

        /// <summary>
        /// 关闭数据库连接
        /// </summary>
        private void Close()
        {

            SqlCon.Close();


        }

        /// <summary>
        /// 连接数据库的私有方法
        /// </summary>
        /// <returns></returns>
        private SqlConnection GetCon()
        {

            if (SqlCon.State == ConnectionState.Closed)
            {
                SqlCon.Open();
            }

            return SqlCon;


        }

        /// <summary>
        /// 处理传过来的sql语句或者存储过程
        /// </summary>
        /// <param name="cmdText">sql语句或者存储过程</param>
        /// <param name="ct">类型</param>
        /// <returns>返回查询的到的databable</returns>
        public DataTable ExecuteQuery(string cmdText, CommandType ct)
        {
            DataTable dt = new DataTable();
            //创建连接
            sCmd = new SqlCommand(cmdText, GetCon());
            //设定类型
            sCmd.CommandType = ct;

            using (sDr = sCmd.ExecuteReader(CommandBehavior.CloseConnection))
            {
                dt.Load(sDr);
                sDr.Close();

            }

            Close();
            return dt;
        }

        /// <summary>
        /// 处理传递进来的带参数的sql语句或是存储过程,返回DataTable
        /// </summary>
        /// <param name="cmdText">带参数的sql语句或是存储过程</param>
        /// <param name="paras">sql参数</param>
        /// <param name="ct">类型</param>
        /// <returns>返回查询的到的datatable</returns>
        public DataTable ExecuteQuery(string cmdText, SqlParameter[] paras, CommandType ct)
        {
            DataTable dt = new DataTable();
            //创建连接
            sCmd = new SqlCommand(cmdText, GetCon());
            //设定类型
            sCmd.CommandType = ct;
            //添加参数
            sCmd.Parameters.AddRange(paras);



            using (sDr = sCmd.ExecuteReader(CommandBehavior.CloseConnection))
            {
                dt.Load(sDr);
                sDr.Close();

            }

            Close();


            return dt;
        }

        /// <summary>
        /// 执行传递进来的sql语句或是存储过程
        /// </summary>
        /// <param name="cmdText">sql语句或是存储过程</param>
        /// <param name="ct">类型</param>
        /// <returns>返回受影响的行数</returns>
        public int ExecuteNonQuery(string cmdText, CommandType ct)
        {
            int res = 0;//用来存储该操作影响的行数
            SqlConnection Sqlcon = GetCon();


            using (sCmd = new SqlCommand(cmdText, Sqlcon))
            {
                //设定类型
                sCmd.CommandType = ct;
                res = sCmd.ExecuteNonQuery();
                Close();

            }

            return res;
        }

        /// <summary>
        /// 执行传递进来的带参数的sql语句或是存储过程
        /// </summary>
        /// <param name="cmdText">sql字符串</param>
        /// <param name="paras">参数</param>
        /// <param name="ct">sql字符串的类型</param>
        /// <returns>返回受影响的行数</returns>
        public int ExecuteNonQuery(string cmdText, SqlParameter[] paras, CommandType ct)
        {
            int res = 0;//用来存储该操作影响的行数

            SqlConnection Sqlcon = GetCon();


            using (sCmd = new SqlCommand(cmdText, Sqlcon))
            {
                //设定类型
                sCmd.CommandType = ct;
                //添加参数
                sCmd.Parameters.AddRange(paras);
                res = sCmd.ExecuteNonQuery();
                Close();

            }


            return res;
        }

        /// <summary>
        /// 批量插入数据
        /// </summary>
        /// <param name="tableName">数据表名称</param>
        /// <param name="dt">要插入的数据</param>
        /// <returns></returns>
        public bool BatchInsertData(string tableName, DataTable dt)
        {
            //数据批量导入sqlserver,创建实例
            System.Data.SqlClient.SqlBulkCopy sqlbulk = new System.Data.SqlClient.SqlBulkCopy(strCon);
            //目标数据库表名
            sqlbulk.DestinationTableName = tableName;
            //数据集字段索引与数据库字段索引映射
            for (int i = 0; i < dt.Columns.Count; i++)
            {
                sqlbulk.ColumnMappings.Add(i, i);
            }

            //导入
            sqlbulk.WriteToServer(dt);

            sqlbulk.Close();
            return true;
        }
    }
}


还有一点想强调和提醒大家的是,同样在上一篇博文中,我的事务处理是B层的事务处理的时候进行的。当然有一点我们是可以肯定的,就是事务处理一定是放在B层。我的做法是直接在B层处理事务。(详见我的上一篇博客)

下面是师兄的意见:

那就是利用面向对象中的“抽象”,再抽象出一个事务管理类,用来管理B层的事务。这样就更加面向对象了。

下面是事务管理类

using System.Data;
using System.Data.SqlClient;
using System.Configuration;
using System.Collections;
using Entity;

namespace DAL
{
    public class TransactionManager
    {
        /// <summary>
        /// 定义连接
        /// </summary>
        SqlConnection sqlConnection = new SqlConnection();
        /// <summary>
        /// 定义事务
        /// </summary>
        SqlTransaction sqlTransaction;


        /// <summary>
        /// 得到连接
        /// </summary>
        /// <returns></returns>
        public SqlConnection GetConnection()
        {
            sqlConnection.ConnectionString = ConfigurationManager.ConnectionStrings["sqlconn"].ConnectionString;
            sqlConnection.Open();
            return sqlConnection;
        }

        /// <summary>
        /// 开启事务
        /// </summary>
        public SqlTransaction TranBegin()
        {
            sqlTransaction = sqlConnection.BeginTransaction();
            return sqlTransaction;
        }
        /// <summary>
        /// 提交事务
        /// </summary>
        public void TranCommit()
        {
            sqlTransaction.Commit();
        }

        /// <summary>
        /// 回滚事务
        /// </summary>
        public void TranRollback()
        {
            sqlTransaction.Rollback();
        }
        /// <summary>
        /// 关闭连接
        /// </summary>
        public void Close()
        {
            sqlConnection.Close();


        }
    }
}

通过和师兄讨论,我们认为两种方法都可以。第一种方法处理更加简单、方便,第二种方法更能体现面向对象的观点。

希望大家提出宝贵意见!!!

你可能感兴趣的:(事务)