日期:2011-06-17  浏览次数:20431 次

另一个走向极端的错误

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

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

 

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%'";