代码中添加事务控制 VS(数据库存储过程+事务) 保证数据的完整性与一致性

        做人事档案的系统考虑到数据的安全性与一致性,毕竟是要对外上线、真正投入使用的项目,数据库的可靠性与安全性上我们开发人员要考虑的就很多了,记得做机房收费系统时注册新卡是自己为了简单,写成了一个存储过程(存储过程加事务),完成了一个功能的实现就万事大吉了,这次想换一种新的方法:经过和师哥的交流学习,在代码中使用事务同样也是可以解决问题的,可以保证数据的正确性,就像银行取款一样,如果在取款的过程中取款机出现故障,我们个人的账户上的金额不会受任何影响等。

 

         代码中使用事务前提:务必保证一个功能(或用例)在同一个打开的数据连接上,放到同一个事务里面操作。



        首先是在D层添加一个类为了保存当前操作的这一个连接放到一个事务中执行,并事务执行打开同一个连接、事务完成关闭同一个连接的一个共有类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Data.SqlClient;
using Maticsoft.DBUtility;
namespace PersonalFiles.DAL
{
    public class DBTransaction
    {
        private DbHelperSQL SqlHelper = null;



        public DBTransaction()
        {
            SqlHelper = new DbHelperSQL();
        }

        /// <summary>
        /// 获取数据库连接
        /// </summary>
        /// <returns></returns>
        public SqlConnection GetConnection()
        {
            return SqlHelper.GetCon();
        }

        /// <summary>
        /// 获取事务
        /// </summary>
        /// <returns></returns>
        public SqlTransaction GetTransaction(SqlConnection conn)
        {
            return conn.BeginTransaction();
        }

        /// <summary>
        /// 提交事务
        /// </summary>
        public void Commit(SqlTransaction sqlTransaction)
        {
            sqlTransaction.Commit();
        }

        /// <summary>
        /// 回滚事务
        /// </summary>
        public void Rollback(SqlTransaction sqlTransaction)
        {
            sqlTransaction.Rollback();
        }

        /// <summary>
        /// 关闭连接
        /// </summary>
        public void Close(SqlConnection conn)
        {

            if (conn.State == ConnectionState.Open)
            {
                conn.Close();
            }

        }
    }
}



        界面层的后台代码和以前一样直接调去就行了,现在来看主要是在B层中的代码发生了很大的变化,需要向下层传递事务与获取的连接


/// <summary>
        /// 增加一条数据
        /// </summary>
        public void Add(PersonalFiles.Model.BasicInformation modelBasic, PersonalFiles.Model.T_HumanAgency model)
        {
            int flag = 0;

            DBTransaction DbTran = new DBTransaction();


            //获得连接
            SqlConnection conn = DbTran.GetConnection();

            

            //开启事务
            SqlTransaction trans = DbTran.GetTransaction(conn);
            try
            {
                //把获得的同一个连接与事务一共传下去
                //dalBasic.Add(modelBasic,conn,trans);
               
                //把获得的同一个连接与事务一共传下去
               
                dalAgency.Add(model,conn,trans);

        


                //事务提交
                DbTran.Commit(trans);
                //return true;
            }

            catch (Exception ex)
            {
                //回滚事务
                DbTran.Rollback(trans);
            }
            finally
            {
                DbTran.Close(conn);
            }
        }


注意的是向D层传是我们需要传的是B层获取的同一个连接于开启的是一个事务:


/// <summary>
        /// 增加一条数据
        /// </summary>
        public void Add(PersonalFiles.Model.T_HumanAgency model,SqlConnection conn,SqlTransaction trans)
        {
            StringBuilder strSql = new StringBuilder();
            strSql.Append("insert into T_HumanAgency(");
            strSql.Append("myidentity,relation,receivemode,workingtime,intotime,oldworkplace,nowworkplace,inervice,registered,registeredcardid,registeredid,householder,isrecord,fileintotime,fileouttime,filetowhere,relationouttime,Paymentstandard,paymentsmonth,payments,stoptime,state,pri,admin,ID)");
            strSql.Append(" values (");
            strSql.Append("@myidentity,@relation,@receivemode,@workingtime,@intotime,@oldworkplace,@nowworkplace,@inervice,@registered,@registeredcardid,@registeredid,@householder,@isrecord,@fileintotime,@fileouttime,@filetowhere,@relationouttime,@Paymentstandard,@paymentsmonth,@payments,@stoptime,@state,@pri,@admin,@ID)");
            SqlParameter[] parameters = {
					new SqlParameter("@myidentity", SqlDbType.VarChar,50),
					new SqlParameter("@relation", SqlDbType.VarChar,50),
					new SqlParameter("@receivemode", SqlDbType.VarChar,50),
					new SqlParameter("@workingtime", SqlDbType.VarChar,50),
					new SqlParameter("@intotime", SqlDbType.VarChar,50),
					new SqlParameter("@oldworkplace", SqlDbType.VarChar,50),
					new SqlParameter("@nowworkplace", SqlDbType.VarChar,50),
					new SqlParameter("@inervice", SqlDbType.VarChar,50),
					new SqlParameter("@registered", SqlDbType.VarChar,50),
					new SqlParameter("@registeredcardid", SqlDbType.VarChar,50),
					new SqlParameter("@registeredid", SqlDbType.VarChar,50),
					new SqlParameter("@householder", SqlDbType.VarChar,50),
					new SqlParameter("@isrecord", SqlDbType.VarChar,50),
					new SqlParameter("@fileintotime", SqlDbType.VarChar,50),
					new SqlParameter("@fileouttime", SqlDbType.VarChar,50),
					new SqlParameter("@filetowhere", SqlDbType.VarChar,50),
					new SqlParameter("@relationouttime", SqlDbType.VarChar,50),
					new SqlParameter("@Paymentstandard", SqlDbType.VarChar,50),
					new SqlParameter("@paymentsmonth", SqlDbType.VarChar,50),
					new SqlParameter("@payments", SqlDbType.VarChar,50),
					new SqlParameter("@stoptime", SqlDbType.VarChar,50),
					new SqlParameter("@state", SqlDbType.VarChar,50),
										new SqlParameter("@admin", SqlDbType.VarChar,50),
                    new SqlParameter("@pri", SqlDbType.VarChar,50),
					new SqlParameter("@ID", SqlDbType.VarChar,50)};
            parameters[0].Value = model.myidentity;
            parameters[1].Value = model.relation;
            parameters[2].Value = model.receivemode;
            parameters[3].Value = model.workingtime;
            parameters[4].Value = model.intotime;
            parameters[5].Value = model.oldworkplace;
            parameters[6].Value = model.nowworkplace;
            parameters[7].Value = model.inervice;
            parameters[8].Value = model.registered;
            parameters[9].Value = model.registeredcardid;
            parameters[10].Value = model.registeredid;
            parameters[11].Value = model.householder;
            parameters[12].Value = model.isrecord;
            parameters[13].Value = model.fileintotime;
            parameters[14].Value = model.fileouttime;
            parameters[15].Value = model.filetowhere;
            parameters[16].Value = model.relationouttime;
            parameters[17].Value = model.Paymentstandard;
            parameters[18].Value = model.paymentsmonth;
            parameters[19].Value = model.payments;
            parameters[20].Value = model.stoptime;
            parameters[21].Value = model.state;
            parameters[22].Value = model.pri;
            parameters[23].Value = model.admin;
            parameters[24].Value = model.ID;
          

            //DbHelperSQL.ExecuteSql(strSql.ToString(), parameters);
            DbHelperSQL.ExecuteSql(strSql.ToString(),conn,trans, parameters);
        }



在代码中添加事务与存储过程中添加事务的异同



     相同点

1:都能够保证数据的一致性。



     不同点:

1:代码中添加事务的好处是:增加了代码的可读性、与可维护性,方便后期人员维护系统看代码能够一目了然的看懂代码,而在数据库中添加存储过程的可读性不是很好。


2:为什么不建议使用数据库自带的存储过程+事务呢?主要是一个项目过多的依赖数据库,这样对后期的数据库迁移都会带来一定的影响与不便(sql向oracle迁移),好多转换不是很容易兼容性和不是很好(以后再深入学习)。


3:合作开发时如果是代码中添加事务遵循了代码上传的原则,这样方便大家的交流。



为什么使用事务可以保证同一个连接向数据库多个表写信息的正确性与一致性的原理:


 事务的原子性

事务的原子性指的是,事务中包含的程序作为数据库的逻辑工作单位,它所做的对数据改操作要全部执行,要么全部不执行。这种特性称为原子性。  事务的原子性要求,如果把一个事务看作是一个程序,它要么完整的被执行,要么完全执行。就是说事务的操纵序列或者完全应用到数据库或者完全不影响数据库。这种特性称为原则性  假如用户在一个事务内完成了对数据库的更新,这时所有的更新对外部世界必须是可见的,或者完全没有更新。前者称事务已提交,后者称事务撤销。DBMS必须确保由成功提交的事物完成的所有操作在数据库内有完全的反映,而失败的事务对数据库完全没有影响


事务的隔离性

 事务开始执行了但是没有提交事务,数据并没有真正的写到数据库里面,当我去断点测试的时候当第一个程序向数据库发出写完时,我去查找数据库不能打开数据库,不能查找,提示连接超时,由于事务的隔离性,数据并没有真正的写到数据库里面,等事务提交才可以查到数据库,可见同一个连接下执行的程序在同一个事务执行的开始于结束后才真正写到数据库里面,如果过程当中保存事务回滚,数据不会写到数据库里面。保证数据的一致性与正确性。



数据的准确性与一致性是我们要时刻考虑的,一个好的系统必须有较好的准确性才能保证用户的使用。






原文地址:https://www.cnblogs.com/javawebsoa/p/3209159.html