C#数据库事务原理及实践之四(转)

另一个走向极端的错误

??满怀信心的新手们可能为自己所掌握的部分知识陶醉不已,刚接触数据库库事务处理的准开发者们也一样,踌躇满志地准备将事务机制应用到他的数据处理程序的每一个模块每一条语句中去。的确,事务机制看起来是如此的诱人——简洁、美妙而又实用,我当然想用它来避免一切可能出现的错误——我甚至想用事务把我的数据操作从头到尾包裹起来。

??看着吧,下面我要从创建一个数据库开始:

using System;
using System.Data;
using System.Data.SqlClient;

namespace Aspcn
{
  public class DbTran
  {
   file://执行事务处理
   public void DoTran()
   {
    file://建立连接并打开
    SqlConnection myConn=GetConn();
    myConn.Open();

    SqlCommand myComm=new SqlCommand();
    SqlTransaction myTran;

    myTran=myConn.BeginTransaction();

    file://下面绑定连接和事务对象
    myComm.Connection=myConn;
    myComm.Transaction=myTran;

    file://试图创建数据库TestDB
    myComm.CommandText="CREATE database TestDB";
    myComm.ExecuteNonQuery();

    file://提交事务
    myTran.Commit();
   }

   file://获取数据连接
   private SqlConnection GetConn()
   {
    string strSql="Data Source=localhost;Integrated Security=SSPI;user id=sa;password=";
    SqlConnection myConn=new SqlConnection(strSql);
    return myConn;
   }
  }

  public class Test
  {
   public static void Main()
   {
    DbTran tranTest=new DbTran();
    tranTest.DoTran();
    Console.WriteLine("事务处理已经成功完成。");
    Console.ReadLine();
   }
  }
}

??//---------------

  未处理的异常: System.Data.SqlClient.SqlException: 在多语句事务内不允许使用 CREATE DATABASE 语句。

at System.Data.SqlClient.SqlCommand.ExecuteNonQuery()
at Aspcn.DbTran.DoTran()
at Aspcn.Test.Main()

??注意,如下的SQL语句不允许出现在事务中:

ALTER DATABASE 修改数据库
BACKUP LOG 备份日志
CREATE DATABASE 创建数据库
DISK INIT 创建数据库或事务日志设备
DROP DATABASE 删除数据库
DUMP TRANSACTION 转储事务日志
LOAD DATABASE 装载数据库备份复本
LOAD TRANSACTION 装载事务日志备份复本
RECONFIGURE 更新使用 sp_configure 系统存储过程更改的配置选项的当前配置(sp_configure 结果集中的 config_value 列)值。
RESTORE DATABASE 还原使用BACKUP命令所作的数据库备份
RESTORE LOG 还原使用BACKUP命令所作的日志备份
UPDATE STATISTICS 在指定的表或索引视图中,对一个或多个统计组(集合)有关键值分发的信息进行更新

??除了这些语句以外,你可以在你的数据库事务中使用任何合法的SQL语句。
事务回滚

??事务的四个特性之一是原子性,其含义是指对于特定操作序列组成的事务,要么全部完成,要么就一件也不做。如果在事务处理的过程中,发生未知的不可预料的错误,如何保证事务的原子性呢?当事务中止时,必须执行回滚操作,以便消除已经执行的操作对数据库的影响。

??一般的情况下,在异常处理中使用回滚动作是比较好的想法。前面,我们已经得到了一个更新数据库的程序,并且验证了它的正确性,稍微修改一下,可以得到:

//RollBack.cs
using System;
using System.Data;
using System.Data.SqlClient;

namespace Aspcn
{
  public class DbTran
  {
   file://执行事务处理
   public void DoTran()
   {
    file://建立连接并打开
    SqlConnection myConn=GetConn();
    myConn.Open();

    SqlCommand myComm=new SqlCommand();
    SqlTransaction myTran;

    file://创建一个事务
    myTran=myConn.BeginTransaction();
    file://从此开始,基于该连接的数据操作都被认为是事务的一部分
    file://下面绑定连接和事务对象
    myComm.Connection=myConn;
    myComm.Transaction=myTran;

    try
    {
     file://定位到pubs数据库
     myComm.CommandText="USE pubs";
     myComm.ExecuteNonQuery();

     myComm.CommandText="UPDATE roysched SET royalty = royalty * 1.10 WHERE title_id LIKE 'Pc%'";
     myComm.ExecuteNonQuery();

     file://下面使用创建数据库的语句制造一个错误
     myComm.CommandText="Create database testdb";
     myComm.ExecuteNonQuery();

     myComm.CommandText="UPDATE roysched SET royalty = royalty * 1.20 WHERE title_id LIKE 'Ps%'";
     myComm.ExecuteNonQuery();

     file://提交事务
     myTran.Commit();
    }
    catch(Exception err)
    {
     myTran.Rollback();
     Console.Write("事务操作出错,已回滚。系统信息:"+err.Message);
    }
   }

   file://获取数据连接
   private SqlConnection GetConn()
   {
    string strSql="Data Source=localhost;Integrated Security=SSPI;user id=sa;password=";
    SqlConnection myConn=new SqlConnection(strSql);
    return myConn;
   }
  }
  public class Test
  {
   public static void Main()
   {
    DbTran tranTest=new DbTran();
    tranTest.DoTran();
    Console.WriteLine("事务处理已经成功完成。");
    Console.ReadLine();
   }
  }
}

??首先,我们在中间人为地制造了一个错误——使用前面讲过的Create database语句。然后,在异常处理的catch块中有如下语句:

myTran.Rollback();

??当异常发生时,程序执行流跳转到catch块中,首先执行的就是这条语句,它将当前事务回滚。在这段程序可以看出,在Create database之前,已经有了一个更新数据库的操作——将pubs数据库的roysched表中的所有title_id字段以“PC”开头的书籍的royalty字段的值都增加0.1倍。但是,由于异常发生而导致的回滚使得对于数据库来说什么都没有发生。由此可见,Rollback()方法维护了数据库的一致性及事务的原子性。

[@more@]

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/8781179/viewspace-924589/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/8781179/viewspace-924589/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值