关于ADO中的隐性事务

KeyLife富翁笔记
作者: HongYuan
标题: 关于ADO中的隐性事务
关键字:
分类: 我学习Delphi,我努力
密级: 保护
(评分: , 回复: 0, 阅读: 230) »»

测试代码:
  ADOQuery1.sql:='select * from region'
  ADOQuery2.sql:='exec SP_test'='select * from region'


  ADOConnection1.BeginTrans;
  ADOQuery1.Post;
 
  //必需发送一次语句重新从数据库提取一次更新后的数据;个人认为同一进程(ADOConnection连接,在SQL Server为一个连接进程,或者一个会话),未提交数据也可以访问,但需人为重新发送一个语句以便从数据库中提出数据返回到数据集TDataSet  
  ADOQuery2.Close;
  ADOQuery2.Open;
  ShowMessage(ADOQuery2.FieldByName('Name').AsString);

  if CheckBox1.Checked then
    ADOConnection1.CommitTrans
  else ADOConnection1.RollbackTrans;
//撤销事务时,因为ADOQuery1做为TDataSet中的数据为修改后,必需刷新一下,ADOQuery2因为修改后,事务提交前重新提过数据,所以现在必需再提一次撤销后数据
  ADOQuery1.Close;
  ADOQuery1.Open;
  ADOQuery2.Close;
  ADOQuery2.Open;

执行跟踪产生的SQL语句与解读:

set implicit_transactions on 开始隐性事务
go
exec sp_executesql N'UPDATE "public".."region" SET "Name"=@P1 WHERE "Code"=@P2 AND "Name"=@P3 AND "Postcode"=@P4 AND "AreaCode"=@P5 AND "Area"=@P6', N'@P1 varchar(7),@P2 varchar(6),@P3 varchar(12),@P4 varchar(2),@P5 varchar(3),@P6 varchar(4)', 'abdasdf', 'efasdf', '111111111111', 'as', 'asd', 'asdf'
--ADOQuery1执行数据修改
go
select * from region
--ADOQuery2执行,这里可以提取到修改后数据,虽然没有提交
go
IF @@TRANCOUNT > 0 COMMIT TRAN 提交事务或IF @@TRANCOUNT > 0 ROLLBACK TRAN回滚
go
set implicit_transactions off 关闭隐性事务
go
select * from region --ADOQuery1重新提取

go
select * from region --adoquery2重新提取

go

注意:
   1.Adoquery1和adoquery2使用同一个ADOConnection1
   2.本事务未结束,则其它进程里无法读取region表数据


2005-11-4 11:55:39   
 2005-11-23 14:39:27    不能返回客户端ADOCONNECTION错误信息,但在查询分析器里可能看到

ALTER   procedure SP_test
  as
  Begin Transaction T_SP_AlterFeeTable

  select * from sysobjects

  RAISERROR ('修改核算数据表异常,系统将自动删除指定的工艺项目数据!', 16, 1)  

  commit transaction T_SP_AlterFeeTable

 
 2005-11-23 14:41:33    可以返回客户端ADOCONNECTION错误信息

ALTER   procedure SP_test
  as
  Begin Transaction T_SP_AlterFeeTable

  RAISERROR ('修改核算数据表异常,系统将自动删除指定的工艺项目数据!', 16, 1)    

  select * from sysobjects  

  commit transaction T_SP_AlterFeeTable

 
 2005-11-23 14:44:22    能返回客户端ADOCONNECTION错误信息,但在查询分析器里可能看到

ALTER   procedure SP_test
  as
  Begin Transaction T_SP_AlterFeeTable

  select * from sysobjects  

  commit transaction T_SP_AlterFeeTable

  RAISERROR ('修改核算数据表异常,系统将自动删除指定的工艺项目数据!', 16, 1)    

 
 2005-11-23 15:59:19    关于Raiserror与ADO分析结果

ADO调用执行存储过程的时都会(SET FMTONLY ON),比如,在ADOQuery2.sql中填入exec sp_test,则相应的程序调用以下代码:
SET FMTONLY ON exec sp_test SET FMTONLY OFF
可见,只要在执行存储过程sp_test时发生异常,仅将元数据返回给客户端,且将不对行进行处理,也不将行作为请求的结果发送到客户端。而RAISERROR,PRINT产生的信息,都将不会返回客户端,但SQLSERVER产生的ERROR信息除外。并且SET FMTONLY在存储过程中全局有效,执行完后则无效。

由上可见,系统不包括的错误信息,比如业务安全检查,需要通过RAISERROR返回信息时,一定要在存储过程中SET FMTONLY OFF RAISERROR('错误',16,1)这样才能在客户端得到错误信息

 
 2005-11-23 16:34:07    最后的测试代码

delphi+ado:

var
  i:Integer;
begin
  try
    ADOConnection1.BeginTrans;
    ADOQuery1.Post;
    with ADOQuery2 do
    begin
      Close;
      SQL.Clear;
      SQL.Add('exec sp_test ');
      Open;
    end;

    ADOConnection1.CommitTrans;

  except
    for i:=0 to ADOConnection1.Errors.Count-1 do
          ShowMessage(ADOConnection1.Errors[i].Description);
    ADOConnection1.RollbackTrans;
    ADOQuery1.Close;
    ADOQuery1.Open;
    //ADOQuery2.Close;
    //ADOQuery2.Open;
  end;

下面是Query2调用存储过程代码

SET QUOTED_IDENTIFIER ON
GO
SET ANSI_NULLS ON
GO
/*
SET FMTONLY ON
exec sp_test
SET FMTONLY OFF
*/
ALTER   procedure SP_test
  as
 
  declare @sql nvarchar(1000),@FiledName varchar(128)
  select top 1 @FiledName='['+isnull(Name,'')+']' from Region

  if rtrim(@FiledName)='[ ]'
  begin
    SET FMTONLY OFF
    RAISERROR ('指定的字段名不能空', 16, 1)
    return
  end

  set @sql ='alter table tt add '+@FiledName+' int'
  Begin Transaction T_SP_AlterFeeTable

  execute(@sql)


  if @@ERROR<>0
  begin
    ROLLBACK transaction T_SP_AlterFeeTable


    select * from tt
    return
  end
  else
  begin

  commit transaction T_SP_AlterFeeTable

  select * from tt
 
  end

GO
SET QUOTED_IDENTIFIER OFF
GO
SET ANSI_NULLS ON
GO

 
 2005-11-23 16:57:39   

  for i:=0 to ADOConnection1.Errors.Count-1 do
          ShowMessage(ADOConnection1.Errors[i].Description);

用raise代替也能提示错误信息

var
  i:Integer;
begin
  try
    ADOConnection1.BeginTrans;
    ADOQuery1.Post;
    with ADOQuery2 do
    begin
      Close;
      SQL.Clear;
      SQL.Add('exec sp_test ');
      Open;
    end;

    ADOConnection1.CommitTrans;

  except
    //for i:=0 to ADOConnection1.Errors.Count-1 do
    //begin
    //      ShowMessage(ADOConnection1.Errors[i].Description);
    //end;

      ADOConnection1.RollbackTrans;
      ADOQuery1.Close;
      ADOQuery1.Open;
      raise;
    //ADOQuery2.Close;
    //ADOQuery2.Open;
  end;
end;

 
 2005-11-23 17:20:08   

只要DELPHI使用try+事务处理,其实就算调用了存储过程执行多步操作,也可以回滚,而不必在存储过程中额外进行事务处理,但如果想部分修改有效的话,就得不使用DELPHI的ADO事务,而使用数据库存储过程中处理事务也可以。

posted @ 2006-11-22 08:39  云水浮萍  阅读(1032)  评论(0编辑  收藏  举报