关于多个DataSet使用事务的讨论

司码君 2007-08-03 05:58:26
代码如下:
try
FPurchase.Connection.BeginTrans;
FPurchase.Save; //1
FPurchaseDetail.Save; //2
FPurchase.Connection.CommitTrans;
except
FPurchase.Connection.RollbackTrans;
on e: Exception do
begin
StatuseInfo(Caption + ':' + e.Message);
end;
end;

FPurchase和FPurchaseDetail用的同一个ADOConnection;
1,2位置的Save方法都是使用的DataSet.UpdateBatch;

问题:
当代码1的保存成功,代码2的保存出现异常回滚的时候,如果用户修改FPurchaseDetail中的数据,再次保存,则代码2处的保存成功,代码1处的保存不会出现异常,但是实际上数据没有能够存入数据库。

个人考虑:
当第一次保存的时候,因为代码1的保存没有出现异常DataSet的状态发生变化,应该变成了浏览状态。
第二次保存时,因为1位置的DataSet已经是浏览状态,而且没有发生变化所以不再保存。而仅仅执行代码2,将明细保存了。

不知是否正确,尝试了一些方法,觉得不妥,是否有更好的方法,大家讨论,谢谢
...全文
312 14 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
14 条回复
切换为时间正序
请发表友善的回复…
发表回复
司码君 2007-08-12
  • 打赏
  • 举报
回复
to:21ithorse

应该是比较可靠,不过很麻烦,如果写好了生成SQL代码的类,以及执行SQL命令的方法,也还可以,属于一劳永逸的方法.

我现在是这样处理的:
不使用批提交方式,新建单据的时候(这个问题主要出现在新建的时候),同时新建一个明细数据,在明细DataSet的BeforePost事件中提交单据头.
laowang2 2007-08-08
  • 打赏
  • 举报
回复
mark
21ithorse 2007-08-07
  • 打赏
  • 举报
回复
这种处理没有写过,不过我可以提意另辟蹊径
adodataset1,adodataset2的recordset取其变化值
再合成SQL回写数据库。自己来处理生成SQL
其实updateBatch也是一样的合成SQL,只不过有一个属性,如果设置成严格更新,
会把所有的字段值当成条件来更新,为避免出现更新覆盖。
===
分享快乐:www.delphichm.com
司码君 2007-08-07
  • 打赏
  • 举报
回复
to kaper :
我已经尝试了很多次,这个问题已经困扰了我很久了,相信不是我一个人有这样的问题。

你的代码是有问题的!

你的判断只是对数据本身的判断,我明白你的意思,就是对所有用户输入的数据进行验证,只有全部符合数据库的约束和规则才能提交。

可是就算所有的数据都能够满足验证,adodataset2.UpdateBatch(); 这一行代码还是可能发生异常的!!比如你在明细选择的产品很可能有其他人已经删除了,这个时候客户端的验证是可以满足的,但是当你提交数据的时候确违背了外键约束,在这种情况下发生异常的时候回滚,如果更换了另一个产品再提交的时候adodataset1.UpdateBatch(); 是不会有任何数据保存的!!

应该还是DataSet的状态变成了UnModified,无法回到历史状态造成的。

不知道我说的是否清晰,感谢kaper。
kaper 2007-08-06
  • 打赏
  • 举报
回复
CREATE TABLE [Master] (
[ID] [int] IDENTITY (1, 1) NOT NULL ,
[BillNo] [varchar] (20) COLLATE Chinese_PRC_CI_AS NULL ,
CONSTRAINT [PK_Master] PRIMARY KEY CLUSTERED
(
[ID]
) ON [PRIMARY]
) ON [PRIMARY]
GO


CREATE TABLE [Detail] (
[ID] [int] IDENTITY (1, 1) NOT NULL ,
[BillID] [int] NULL ,
[ProductID] [varchar] (20) COLLATE Chinese_PRC_CI_AS NULL ,
[A] [int] NULL ,
[B] [int] NULL ,
[C] AS ([A] - [B]) ,
CONSTRAINT [PK_Detail] PRIMARY KEY CLUSTERED
(
[ID]
) ON [PRIMARY]
) ON [PRIMARY]
GO



你自己先试试看嘛
kaper 2007-08-06
  • 打赏
  • 举报
回复
我试过了 只要修改后 if adodataset2.FieldByName( "ProductID ").AsString= " " then 满足了这个条件 就可以提交上去了 2个表都提交上去的 是一起提交的
司码君 2007-08-05
  • 打赏
  • 举报
回复
to china618 上面的代码是我写的不大好,你说的是对的
to kaper 你的代码如果继续修改adodataset2里面的数据直到满足要求,第二次提交的时候稍adodataset1是会提交的,但是,数据没有写到数据库,因为现在sataset的状态是UnModified,这个问题其实很多人发现了,只是现在好像没有人继续讨论了,我就问问,是不是大家都已经有了解决的方法了?

http://www.delphibbs.com/delphibbs/dispq.asp?lid=2090654
下面有很长的讨论,大家可以看看,保存文件据说很好,不过如果操作的表超过2个,保存文件也有点力不从心了

下面是一个方法,但是我认为没有实际上解决问题
http://www.01cn.net/cgi-bin/threaded_show.cgi?tid=2332&h=1&bpg=1&age=0
china618 2007-08-04
  • 打赏
  • 举报
回复
BeginTrans应在try前
如LS
kaper 2007-08-04
  • 打赏
  • 举报
回复
都会提交上去的

procedure TForm1.Button1Click(Sender: TObject);
begin
adoconnection1.BeginTrans;
try
adodataset1.UpdateBatch();
if adodataset2.FieldByName('ProductID').AsString='' then
raise exception.Create('ProductID not null');
adodataset2.UpdateBatch();
adoconnection1.CommitTrans;
except
adoconnection1.RollbackTrans;
end;
end;
司码君 2007-08-03
  • 打赏
  • 举报
回复
第一次大家都会回滚,但是,第二次的时候就不一样了,因为更正了明细上的数据,所以明细是可以提交的,但是主表由于第一次已经提交,state已经是浏览,所以不会再次提交。而且修改之后也不能提交!
kaper 2007-08-03
  • 打赏
  • 举报
回复
D的事务是针对adoConnection的, 只要2个DataSet连的是同一个adoConnection那
adoConnection.BeginTrans;
adodataset1.UpdateBatch();
adodataset2.UpdateBatch();
。。。
。。。
adoConnection.CommitTrans;

只要中间有异常 都会回滚
司码君 2007-08-03
  • 打赏
  • 举报
回复
FPurchase.Connection.RollbackTrans;
这个代码应该在异常内部,上面写的有点小问题,但是不影响讨论啊
司码君 2007-08-03
  • 打赏
  • 举报
回复
自己顶一个,还是用Delphi的人少了啊?
brightyang 2007-08-03
  • 打赏
  • 举报
回复
sf

2,507

社区成员

发帖
与我相关
我的任务
社区描述
Delphi 数据库相关
社区管理员
  • 数据库相关社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧