事务小结

来源:互联网 发布:中小型企业erp软件 编辑:程序博客网 时间:2024/06/06 08:11

    事务在时已经接触,但是迟迟没有使用,正好遇到这次项目锻炼机会,使用了一把。

事务

    事务(Transaction)是访问,更新数据库中的一个程序执行单元。事务通常由数据库语言或程序的执行所引起,事务由事务开始(begin transaction)和事务结束(end transaction)之间执行的全体操作组成。
    事务是恢复和并发控制的基本单位,事务应该具有4个属性:原子性、一致性、隔离性、持久性,这四个属性通常称为ACID特性。

  • 原子性(atomicity),一个事务是一个不可分割的工作单位,事务中包括的多个操作,要么都做,要么都不做。
  • 一致性(consistency),事务必须是使数据库从一个一致性状态变到另一个一致性状态,一致性与原子性是密切相关的。
  • 隔离性(isolation),即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
  • 持久性(durability),指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。接下来的其他操作或故障不应该对其有任何影响。

连接

    好吧,说的有点复杂,事务的目的很简单:你要做一系列的事,要么一口气全部完成;如果中间任何一项出错,大家全部恢复事务前的状态,话说有点“同生共死”的感觉。

    不过这个恢复到以前的状态说的有点扯,并不是所有的都能恢复,我在文本框中输入了一些文字,点击按钮触发了一个事务,事务失败了,文本框自动清空了?当然不是,此处的“恢复”指的是对数据库操作的数据恢复。

    咱接着说,既然是对数据库的恢复,必然离不开与SQL连接的关联,对,在开发中,谁和谁组成事务的依据就是数据库连接,也就是SqlConnection。

事务

        考试系统中涉及到成绩转移,既然转移,必然涉及到数据的插入和删除两个步骤,所以在此处使用事务:当在历史表中插入某一条成绩数据成功时,在原数据表中删除该条记录。
    因为UI层仅仅是传递一些实体数据,SqlHelper类也只是抽象出对数据库的一些操作,所以次数省略UI层类和SqlHelper类。

BLL层

        转移分数逻辑:先插入再删除。

public bool MoveScore(DataTable dt)        {            //建立事务            DBTransaction dbTran = new DBTransaction();            //获取连接            SqlConnection sqlConn = dbTran.GetConnection();            SqlTransaction sqlTran = dbTran.GetTransaction(sqlConn);            //开启事务            try         {                                HistoryDataDAL historyDAL = new HistoryDataDAL();                ScoreHistoryEntity enScoreHistory = new ScoreHistoryEntity();                ScoresEntity enScore = new ScoresEntity();                //循环执行转移操作                for (int i = 0; i < dt.Rows.Count; i++)                {                    //将表格转换为实体                    enScoreHistory.ExamId = dt.Rows[i]["考试ID"].ToString();                    enScoreHistory.ExamName = dt.Rows[i]["考试名称"].ToString();                    enScoreHistory.Score = dt.Rows[i]["成绩"].ToString();                    enScoreHistory.StudentCode = dt.Rows[i]["学号"].ToString();                    enScoreHistory.StudentName = dt.Rows[i]["姓名"].ToString();                    //转换为分数实体                    enScore.ExamId = dt.Rows[i]["考试ID"].ToString();                    enScore.StudentId = dt.Rows[i]["学号"].ToString();                    //如果哪个学生成绩转移失败,给出提示                    if (historyDAL.MoveScore(enScoreHistory, sqlTran, sqlConn) == false || historyDAL.DeleteScoresByStuIdAndExamId(enScore , sqlTran, sqlConn) == false)                    {                        throw new Exception("学号为: " + enScoreHistory.StudentCode + "姓名为: " + enScoreHistory.StudentName + "考试为: " + enScoreHistory.ExamName + "的成绩转移失败,请重新转移剩余学生成绩!");                    }                }                sqlTran.Commit();                //执行到这里返回true                return true;        }        catch (Exception moveScoreException)        {                sqlTran.Rollback();                throw moveScoreException;        }                        finally            {                sqlConn.Close ();            }        }

事务类

       DBTransaction:这个类主要负责事务的创建、提交、回滚、及关闭数据库连接函数。

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Data;using System.Data.SqlClient;public class DBTransaction{    /// <summary>    /// 根据配置文件中得变量sqlConn得到连接字符串    /// </summary>    private  string strCon = ConfigurationManager.ConnectionStrings["sqlConn"].ConnectionString;    /// <summary>    /// 定义一个连接    /// </summary>    private  SqlConnection sqlCon;    /// <summary>    /// 获取数据库连接    /// </summary>    /// <returns></returns>    public SqlConnection GetConnection()    {        sqlCon = new SqlConnection(strCon);        if (sqlCon.State == ConnectionState.Closed)        {            sqlCon.Open();        }        return sqlCon;    }    /// <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();        }    }}

DLL层

        转移分数方法:在成绩历史表中插入一条成绩数据。

/// <summary>/// 移动成绩到历史表中/// </summary>/// <param name="enScoreHistory">历史成绩试题</param>/// <returns>是否转移成功</returns>public bool MoveScore(ScoreHistoryEntity enScoreHistory, SqlTransaction sqlTran, SqlConnection sqlConn){    try    {        //SQL语句        string SqlTxt = "insert into TEH_ScoresHistory (StudentCode,StudentName,ExamName,Scores,ExamId) values(@StudentCode,@StudentName,@ExamName,@Scores,@ExamId)";        SqlParameter[] paras = { new SqlParameter("@StudentCode", enScoreHistory.StudentCode), new SqlParameter("@StudentName", enScoreHistory.StudentName), new SqlParameter("@ExamName", enScoreHistory.ExamName), new SqlParameter("@Scores", enScoreHistory.Score), new SqlParameter("@ExamId", enScoreHistory.ExamId), };        //执行结果        int  intMoveScore = sqlHelper .ExecNoSelect(SqlTxt, paras, CommandType.Text,sqlConn,sqlTran);        //根据返回值判断是否转移成功        if (intMoveScore > 0)        {            return true;        }        else        {            sqlTran.Rollback();            return false;        }    }    catch (Exception MoveScoreException)    {        sqlTran.Rollback();        throw MoveScoreException;    }}

        删除原数据方法:在原表中删除该条成绩数据。

/// <summary>/// 根据考试号和学号删除一门成绩/// </summary>/// <param name="enScores">考试实体</param>/// <param name="sqlTran">事务</param>/// <param name="sqlConn">连接</param>/// <returns>是否删除成功</returns>public bool DeleteScoresByStuIdAndExamId(ScoresEntity  enScores, SqlTransaction sqlTran, SqlConnection sqlConn){    try    {        string SqlTxt = "delete from TEB_Scores where ExamId=@ExamId and StudentId=@StudentId";        SqlParameter[] paras = { new SqlParameter("@ExamId", enScores.ExamId), new SqlParameter("@StudentId", enScores.StudentId) };        int intDelExamArr = sqlHelper.ExecNoSelect(SqlTxt, paras, CommandType.Text, sqlConn, sqlTran);        //大于零则删除成功        if (intDelExamArr <= 0)        {            sqlTran.Rollback();            return false;        }        return true;    }    catch (Exception DelSocresException)    {        sqlTran.Rollback();        throw DelSocresException;    }}

        由代码可以看出,在整个事务中,传递的是同一个数据库连接;因为事务提交或是回滚后,事务已经结束,所以要注意,错误处理时,一定要避免事务的二次提交或回滚。

数据库中的事务

    事务同样存在于存储过程等中,以下即是和上面逻辑相同,但是简单化的一个存储过程.

USE BasicDataSystemSET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGO-- =============================================-- Author:<李达>-- Create date: <2013年3月17日>-- Description:<成绩转移>-- =============================================CREATE PROCEDURE Proc_MoveScores-- 声明学号变量   @StudentCode varchar(50)ASBEGIN-- 启动事务BEGIN TRAN--添加一条成绩到历史表INSERT INTO TEH_ScoresHistory (StudentId) VALUES (@StudentCode)--删除该原成绩DELETE FROM TEB_Scores  WHERE StudentId =@StudentCode    --出现错误则回滚if @@ERROR <>0ROLLBACK TRAN--否则提交事务ELSECOMMIT TRANENDGO

总结

    当然这个事务例子比较简单,参与的逻辑也比较少,但是"麻雀虽小五脏俱全",再复杂的事务也是基于简单之上。

    把握不变的,其它任它变。