A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 张少甫 中级黑马   /  2012-9-19 20:57  /  1847 人查看  /  2 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 张少甫 于 2012-9-20 07:56 编辑

开发项目过程中,经常听到同事说程序报错,是事务回滚了。对于这个我比较欠缺,还没有概念。什么是事务,那什么是事务回滚。请懂的高手指点下。最好有点具体的例子。

评分

参与人数 1技术分 +1 收起 理由
宋天琪 + 1

查看全部评分

2 个回复

正序浏览
  事务是SQL中的单个逻辑工作单元,一个事务里的所有语句被作为整体执行
  遇到错误时,可以回滚事务内的所有改变,从而保证数据库的一致性和可恢复性
  一个逻辑工作单元必须具有四种属性,也称为ACID
  ·事务的四种属性
  1)原子性(Atomicity):一个事物必须作为工作的原子单位,它所做的数据修改要么全部执行,要么全部取消
  2)一致性(Consistency):当事务完成后,所有数据必须处于一致状态,即:事务所修改的数据必须遵循数据库中各种约束、规则要求,保持数据的完整性
  3)隔离性(Isolation):一个事务所做的修改必须能够与其他事务所作的修改隔离开来;在并发处理过程中,一个事物所看到的数据状态必须为另一个事务处理前或后的数据
  4)永久性(Durability):事务完成后,它对数据库所做的修改被永久保留下来。事务日志保证事务的永久性
  ·事务的分类
  1)显示事务:由用户执行T-SQL事务语句而定义的事务,又称为用户定义事务
  2)隐士事务:当前事务提交或回滚后,SQL自动开始的事务。使用inplicit_transations选项打开隐士事务。
  3)自动事务模式:在自动事务模式下,当一个语句被成功执行后,它被自动提交,而当它执行过程中产生错误事,则被自动回滚。自动事务模式是SQL单位默认管理模式

  ·举例:
------数据库中的事务
      银行转账: 李四转500给张三
BEGIN
    DECLARE @AccountMoney1 int;
    DECLARE @AccountMoney2 int;
    SET @AccountMoney1=0;
    SET @AccountMoney2=0;
    BEGIN TRAN                                   --定义事物
UPDATE TEST
SET @AccountMoney1=AccountMoney=AccountMoney+500
WHERE AcountName='张三'
UPDATE TEST
SET @AccountMoney2=AccountMoney=AccountMoney-500
WHERE AcountName='李四'
PRINT  @AccountMoney1;
PRINT   @AccountMoney2;
IF(@AccountMoney1=@AccountMoney2)
  COMMIT TRAN                              --提交事物
ELSE
     ROLLBACK TRAN                            --回滚事物
END
-----------------------C#中的事务
/// <summary>
        /// 本地事物
        /// </summary>
        public void LocaltionTransactionDemo()
        {
            int intResult = 0;
            string strCon = "Data Source=.;Initial Catalog=DB_TRANS;Integrated Security=True";

            string strSQL = @"UPDATE TEST
                            SET AccountMoney=AccountMoney+500
                            WHERE AcountName='张三'
                            UPDATE TEST
                            SET AccountMoney=AccountMoney-500
                            WHERE AcountName='李四'";
      
            using (SqlConnection con = new SqlConnection(strCon))
            {
                con.Open();
                SqlTransaction st = con.BeginTransaction();                    //定义事物
                SqlCommand com = new SqlCommand(strSQL, con);
                com.Transaction = st;                                          //事物赋值给SqlCommand

                try
                {
                    intResult = com.ExecuteNonQuery();
                    st.Commit();                                               //提交事物
                }
                catch (Exception e1)
                {
                    st.Rollback();                                             //回滚事物
                }
            }
            Console.WriteLine("执行影响的行数: {0}",intResult);
        }

        public void Demo1()
        {
            int intResult = 0;
            string strCon = "Data Source=.;Initial Catalog=DB_TRANS;Integrated Security=True";

            string strSQL = @"UPDATE TEST
                            SET AccountMoney=AccountMoney+500
                            WHERE AcountName='张三'";

            using (SqlConnection con = new SqlConnection(strCon))
            {
                con.Open();
                SqlCommand com = new SqlCommand(strSQL, con);
                intResult = com.ExecuteNonQuery();
            }
            Console.WriteLine("执行影响的行数: {0}", intResult);      
        }

        public void Demo2()
        {
            int intResult = 0;
            string strCon = "Data Source=.;Initial Catalog=DB_TRANS;Integrated Security=True";

            string strSQL = @"UPDATE TEST
                            SET AccountMoney=AccountMoney-500
                            WHERE AcountName='李四'";

            using (SqlConnection con = new SqlConnection(strCon))
            {
                con.Open();
                SqlCommand com = new SqlCommand(strSQL, con);
                intResult = com.ExecuteNonQuery();
            }
            Console.WriteLine("执行影响的行数: {0}", intResult);         
        }

        /// <summary>
        /// 分布式事物
        /// </summary>
        public void DistributeTransactionDemo()
        {
            using(TransactionScope ts=new TransactionScope(TransactionScopeOption.Required))
            {
                this.Demo1();
                this.Demo2();
                ts.Complete();                                                 //事物提交
            }
        }

评分

参与人数 1技术分 +2 收起 理由
宋天琪 + 2

查看全部评分

回复 使用道具 举报
事务(Transaction)是访问并可能更新数据库中各种数据项的一个程序执行单元(unit)。事务通常由高级数据库操纵语言或编程语言(如SQL,C++或Java)书写的用户程序的执行所引起,并用形如begin transaction和end transaction语句(或函数调用)来界定。事务由事务开始(begin transaction)和事务结束(end transaction)之间执行的全体操作组成。

例如:在关系数据库中,一个事务可以是一条SQL语句,一组SQL语句或整个程序。

事务是恢复和并发控制的基本单位。

事务应该具有4个属性:原子性、一致性、隔离性、持续性。这四个属性通常称为ACID特性。

原子性(atomicity)。一个事务是一个不可分割的工作单位,事务中包括的诸操作要么都做,要么都不做。

一致性(consistency)。事务必须是使数据库从一个一致性状态变到另一个一致性状态。一致性与原子性是密切相关的。

隔离性(isolation)。一个事务的执行不能被其他事务干扰。即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。

持久性(durability)。持续性也称永久性(permanence),指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。接下来的其他操作或故障不应该对其有任何影响。


我为什么要使用事务? 俺这里再举个很俗很俗的例子:

俺到银行存钱,于是有这么几个步骤:
1、把钱交给工作人员;2、工作人员填单;3、将单子给我签字;4、工作人员确认并输入电脑。

要是,要是我把钱交给工作人员之后,进行到3我签字了。那哥们突然心脏病发作,over掉了,那,我的钱还没有输入电脑,但我却交了钱又签字确认了,而并没有其他任何记录。我岂不是要亏死了???我的血汗钱啊!赶紧退给我!!

于是,在数据库里产生了这么一个术语:事务(Transaction),也就是要么成功,要么失败,并恢复原状。

还是写程序把:

Create Proc sp我去存款(@M Money , @iOperator Int)
As
Begin
Declare @i int

Begin Tran           --激活事务
Exec @i=sp交钱 @m,@iOperator
if @i<>0           --这里一般用系统错误号 @@Error。 我这里为了举例子没有用到。需要根据实际情况。
begin
Rollback Tran                   --回滚事务
RaisError ('银行的窗口太少了,我懒得排队,不交了!:( ', 16, 1) with Log --记录日志
Return -1                     --返回错误号
end

Exec @i=sp填单 @m,@iOperator
if @i<>0
begin
Rollback Tran                   --回滚事务
RaisError ('银行的哥们打印机出了点毛病,打印不出单子来,把钱退回来给我吧??', 16, 1) with Log
Return -2                     
end

Exec @i=sp签字 @m
if @i<>0
begin
Rollback Tran                   --回滚事务
RaisError ('我 靠?什么烂银行,换了3支笔都写不出水来!!老子不存了!!不签!', 16, 1) with Log
Return -3                     
end

Exec @i=sp输入电脑 @m,@iOperator
if @i<>0
begin
Rollback Tran                   --回滚事务
RaisError ('什么意思?磁盘空间已满?好了好了,把钱给我,我到旁边的这家银行!', 16, 1) with Log
Return -4                     
end

Commit Tran        --提交事务
Return 0
End

评分

参与人数 1技术分 +2 收起 理由
宋天琪 + 2

查看全部评分

回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马