AdoConnection中开事务,后台存储过程也开事务,有没有问题?为什么?(300分)

  • 主题发起人 主题发起人 wangfu
  • 开始时间 开始时间
W

wangfu

Unregistered / Unconfirmed
GUEST, unregistred user!
后台存错过程对多个表进行操作,所以进行了事务处理
前台delphi一次调用多个存储工程,所以也开事务处理,会不会出现什么问题?
另,这2个事务有什么不同之处。不知道我说清楚没有
 
不同事务对应不同存储过程啊,应该可以的
 
没有问题,事务是可能嵌套的,但这样做好象没必要
 
怎么没有必要,调用任何一个存储过程出错,其他的对所有存储过程的操作都要回滚啊
 
一个是数据库自动控制,一个是你程序控制,
其实我也不太清楚了,我总觉得没有必要搞的这么麻烦。
再说测试过后,一般执行都会正常的,
而且你要几个存储过程连续执行,你可以试着把它放到一个存储过程里执行
不就行了吗?
 
可以呀,事务管理是很必要的,这对程序的正常运行和资料的完整具有保障功能。
 
to glbboy:
就是放到一个存储过程不方便啊,前台要循环多次调用一个存储过程的,而且循环那些
要在前台提供的
 
没有问题,我用D5+BDE+SQL Server就这么做,如果程序中的事物回滚,存储过程中的事物
的递交也全部回滚。
 
这么做不是没有必要,业务分解的细的话,存储过程之间要相互调用,有的存储过程即是
独立的业务处理过程,也会被其他过程调用,这些存储过程中必须要用事物,其实就是用
到了事物的嵌套,很有必要,因为delphi不支持事物嵌套,用程序中的事物加存储过程中
的事物完成事物嵌套比在delphi中实现方便。
 
事务嵌套?
似乎是不行。
记得当初曾经在Oracle 7.3.4(Sco下)和Delphi5 BDE下进行过类似的测试,结果是:
一旦存储过程提交了,那么在客户端RollBack是不行的。
SQL Server下没有试验过。

不过进行一些BDE/ADO的设置到不知道是否可以。。。
 
存储过程内容为:
CREATE PROCEDURE abcdef AS
insert into Table2 values('1','2')
commit

Delphi代码为
procedure TForm1.Button1Click(Sender: TObject);
begin
try
ADOConnection1.BeginTrans;
ADOStoredProc1.ExecProc;
ADOConnection1.RollbackTrans;
except
end;
end;

执行结果:点击按钮两次,两条结果都插入到了Table2中!
Ado取默认设置。
 
会有问题的, 因为无论是ADO的事务或者SQL段存储过程的事务
其结果都是使用了服务器端的事务, 虽然事务可以多级嵌套, 但是其
中任何一级发出回滚命令都会导致全部事务的回滚,
具体可以参考SQL 联机帮助中的SAVE TRANSACTION 和
begin transaction 等命令

我写了专门判断事务嵌套等级的语句, 摘录如下,请参考

SELECT @cproc_name = 'sl_aj_rcyw_dzjz: '
,@terror_mess ='发生未定义错误!' --设置缺省的错误信息, 当事务正常结束时置空

-- ************ 开始事务 **********
if @@trancount =0 --若尚未启动事务
begin
BEGIN TRANSACTION aj_rcyw_dzjz
select @itran=0
end
else
begin
save transaction aj_rcyw_dzjz
select @itran=1
end

--以下部分判断传递的 参数 是否正确合理
IF @@nestlevel =0 --如果本存储过程在最上一级
BEGIN
-- .......................................
if 错误 goto xerror1
END

/*..................................
...................................你的处理过程
if 错误 goto xerror1
....................................
*/

SELECT @terror_mess=' ' --置错误信息为空

if @itran=0
commit TRANSACTION aj_rcyw_dzjz
if @@nestlevel =1 --如果当前过程是最上一级, 则返回结果集
SELECT 'ferror_mess'=@terror_mess --错误信息可能为空, 也可能含有一些提示,如:'该户已结息'
RETURN 0 --返回正确的信息号
/* ********************************************************************** */
xerror1:
ROLLBACK transaction aj_rcyw_dzjz
if @@nestlevel =1 --如果当前过程是最上一级, 则返回结果集
SELECT 'ferror_mess' =ltrim(rtrim(@cproc_name)) + @terror_mess

RETURN -6 --发生其它用户错误


 
我用D5+BDE+SQL Server就这么用的,Oracle没用过。
 
to dirk,你是否进行过其他设置?
我上面给出的测试代码就是在SQL Sever 7.0、 Ado下测试的呀。
BDE下应该没有任何区别的。我本地没有SQL SErver for bde的驱动,所以暂时测试不了。
 
不好意思, 漏了一点, 上级存储过程(或者DELPHI前台)调用存储过程时
应该加上输出参数 ,

@terror_mess char(100) =' ' output --返回参数: 错误信息
如果该参数内容不为空, 则说明调用失败, 如果当前事务是最高一级则
立即回滚, 否则, 再将错误信息向更上一级的存储过程(或者调用单元)传递
 
我的使用方式如下:
function TAccountTransferForm.Save: Boolean;
var
sInputUser, sSignUser: string;
dtInputTime, dtSignTime: TDateTime;
i, iCount, iID, iCheck: Integer;
Node: TdxTreeListNode;
begin
if not FChanged then
begin
Result := True;
Exit;
end;
Result := False;
UpdateTL;
iCount := dxTL.Count;
DMBase.adocnBiz.BeginTrans; //
for i := 0 to iCount - 1 do
begin
Node := dxTL.Items;
iCheck := Node.Values[Integer(aclCheck)];
iID := Node.Values[Integer(aclID)];
if (iCheck = 1) or (iID <> 0) then
begin
try //保存操作,后台sqlServer中也有事务处理
Result := DMAccountTransfer.SaveAccountTransfer(iID,
Node.Values[Integer(aclAID)], Node.Values[Integer(aclOutAccount)],
Node.Values[Integer(aclInAccount)], Node.Values[Integer(aclBalance)], Node.Values[Integer(aclOutUID)],
rzedtInUnit.tag, Node.Values[Integer(aclOutBankID)],
rzcbBank.ItemIndex + 1,StrToDateTime(Node.Values[Integer(aclCDate)]),
StrToDateTime(Node.Values[Integer(aclFactDate)]),StrToCurr(Node.Values[Integer(aclFactMoney)]),
StrToCurr(Node.Values[Integer(aclAccrual)]), StrToDateTime(Node.Values[Integer(aclEndMonth)]),
Node.Values[Integer(aclTag)],Node.Values[Integer(aclMemo)],
sInputUser, dtInputTime, sSignUser, dtSignTime);
if (Result = True) and (iCheck = 1) and (Node.Values[Integer(aclSignTag)] = 1) then
begin //审批操作,也有事务操作
Result := DMAccountTransfer.SignAccountTransfer(iID, sSignUser, dtSignTime);
end;
if Result = True then
begin
if iCheck = 1 then
Node.Values[Integer(aclID)] := iID
else
Node.Values[Integer(aclID)] := 0;
end;
except
DMBase.adocnBiz.RollbackTrans;
raise;
Exit;
end;
end;
end;

DMBase.adocnBiz.CommitTrans;
FChanged := False;
FModifing := (rzrgSignTag.ItemIndex = 0);
EnableControls;
end;

我的目的如下:
就是保存之前要测试一下这个用户到底有没有审批的权限,如果没有,那么他只能保存
未审批的记录,已经审批的记录,只能让具有审批权限的人修改保存。
好像没有什么问题。

请大家看看。
 
没有什么其他设置,代码贴出来你看看:

procedure TFrm_UserPower.Acti_adduserExecute(Sender: TObject);//新增用户
var
i:integer;
FTN:TTreeNode;
begin
Frm_NewUser:=TFrm_NewUser.Create(self);
Frm_NewUser.GroupOrUser :=0;
Frm_NewUser.IsEdit :=false;
if Frm_NewUser.ShowModal =mrOk then
begin
try
GU:=nil;
DM_Power.Dbc.StartTransaction ; //开始事务
DM_Power.SP_P1.StoredProcName :=SP_Add_User; //执行添加一个用户存储过程
DM_Power.SP_P1.Prepare ;
DM_Power.SP_P1.ParamByName('@UserName').AsString :=trim(Frm_NewUser.Edt_username.Text) ;
DM_Power.SP_P1.ParamByName('@UserPwd').AsString :=Frm_NewUser.Edt_mm1.Text ;
DM_Power.SP_P1.ExecProc ;
if DM_Power.SP_P1.ParamByName('RETURN_VALUE').AsString ='0' then //如果存储过程执行正确
begin
new(GU); //申请组、用户结构
GU.NodeType :=piUser;
GU.ID := DM_Power.SP_P1.ParamByName('@Serial').AsString; //得到由存储过程返回的Serial
for i := 0 to Frm_NewUser.LB_group.Items.Count -1 do
begin
if not AddUserToGroup(Frm_NewUser.LB_group.Items,GU.ID) then //保存隶属于组信息,如果出错
begin
DM_Power.Dbc.Rollback ;
dispose(GU);
Application.MessageBox('在保存用户组信息时出错!','信息',MB_ICONINFORMATION);
exit;
end;
end;
FTN:=TV_groupuser.Items.AddObject(nil,Frm_NewUser.Edt_username.Text,GU);
FTN.ImageIndex := Img_user;
FTN.SelectedIndex :=Img_user;
DM_Power.Dbc.Commit ;
end
else begin
DM_Power.Dbc.Rollback ;
Application.MessageBox(pchar('在新建用户时出错,返回错误代码:'+DM_Power.SP_P1.ParamByName('RETURN_VALUE').AsString),'出错消息',MB_ICONERROR);
end;
except
DM_Power.Dbc.Rollback ;
if GU<>nil then dispose(GU);
Application.MessageBox('在新建用户时出错!','出错消息',MB_ICONERROR);
end;
end;
Frm_NewUser.Free ;
end;

存储过程:
CREATE Procedure sp_AddAUser --添加新用户
(@UserName varchar(40),@UserPwd char(12),@Serial char(12) output)
As
declare @FE int
if @UserName='' or @UserPwd=''
return -1
else
begin
BEGIN TRANSACTION
execute @FE=sp_GetMaxSerial 'sys_user',@Serial output
if @FE=0
begin
insert into sys_user ([user_id],[user_name],[user_pwd]) values (@Serial,@UserName,@UserPwd)
if @@error=0
begin
COMMIT TRANSACTION
return 0
end
else
begin
ROLLBACK TRANSACTION
return -1
end
end
else
begin
ROLLBACK TRANSACTION
return @FE
end
end
go

就是这些,在存储过程和程序中都有事物处理,程序中回滚,所有的都回滚,应该没问题的。
 
这样是可以的,但是你要注意事务,不然会产生一些问题。
 
多人接受答案了。
 
后退
顶部