起步软件技术论坛-X3

 找回密码
 立即注册
搜索
楼主: liso

[请求]在一个事务中多次更新同一记录的问题**

[复制链接]
 楼主| 发表于 2008-3-3 13:16:52 | 显示全部楼层
有****围起来的这些代码,可能会多次对同一条记录进行更新
回复 支持 反对

使用道具 举报

 楼主| 发表于 2008-3-3 13:18:18 | 显示全部楼层
我把整个事件的代码再贴一下
procedure TINVOICE_MANAGE.DSB_INV_BILL_DETAILBeforeApplyUpdates(DataSet: TDataSet);
var lDeltaDataSet : TDeltaDataSet;
  lQuery,lQueryex:TQuery;
  ls_sql :string;
  ls_new_billid, ls_old_billid, ls_bill_inv_status :string;
  lf_new_inv_fee, lf_old_in_fee, lf_inv_available_valuta:float;
  li_count:Integer;
begin
  if  DSB_INV_BILL_DETAIL.DataSet.Active and not DSB_INV_BILL_DETAIL.DataSet.UpdatesPending  then
   Exit;
   lQueryex := TDbCommand.CreateConnect(DSB_INV_BILL_DETAIL.DataSet);
   lDeltaDataSet:= TDeltaDataSet.Create(DSB_INV_BILL_DETAIL.DataSet);

   try
     while not lDeltaDataSet.Eof do
     begin
       case lDeltaDataSet.UpdateKind of
        //修改                                                                              `
         TUpdateKind.ukModify:
         begin
           ls_new_billid := lDeltaDataSet.FieldByName('EIBD_BILLID').AsString;
           lf_new_inv_fee := lDeltaDataSet.FieldByName('EIBDCstdTtl').AsFloat;
           lDeltaDataSet.Prior;
           ls_old_billid := lDeltaDataSet.FieldByName('EIBD_BILLID').AsString;
           lf_old_in_fee := lDeltaDataSet.FieldByName('EIBDCstdTtl').AsFloat;
           If lf_new_inv_fee = '' then lf_new_inv_fee := lf_old_in_fee;
           If ls_new_billid = '' then ls_new_billid := ls_old_billid;
           lDeltaDataSet.Next;
           //恢复结算单开票金额
           ls_sql := 'SELECT COUNT(EBH_AUTOIN) lcount FROM EXP_BILL_HEAD WHERE EBH_AUTOIN = ' + QuotedStr(ls_old_billid);
           lQuery := TDbCommand.OpenSql(ls_sql);
           li_count := 0;
           while not lQuery.Eof do
           begin
             li_count := lQuery.FieldByName('lcount').AsInteger;
             lQuery.Next;
           end;
           lQuery.EmptyDataSet;
           If li_count = 1 Then
           begin
             ls_sql := 'SELECT EBH_INV_VALUTA  FROM EXP_BILL_HEAD WHERE EBH_AUTOIN = ' + QuotedStr(ls_old_billid);
             lQuery := TDbCommand.OpenSql(ls_sql);
             lf_inv_available_valuta := lQuery.FieldByName('EBH_INV_VALUTA').AsFloat;

             If lf_inv_available_valuta < lf_old_in_fee Then
             begin
               Business.Forms.Dialogs.ShowMessage('恢复结算单开票金额时出错:编号为' + ls_old_billid + '的结算单的已开票金额,不够扣减。');
               SysUtils.Abort;
             end;

             If lf_inv_available_valuta - lf_old_in_fee = 0 Then
             begin
               ls_bill_inv_status := '20';
             end
             Else
             begin
               ls_bill_inv_status := '40';
             end;

             ls_sql := 'UPDATE EXP_BILL_HEAD SET EBH_INV_VALUTA = EBH_INV_VALUTA - ' +  floattostr(lf_old_in_fee) +
                        ', EBH_STATUS = ' + QuotedStr(ls_bill_inv_status) + 'WHERE EBH_AUTOIN = ' + QuotedStr(ls_old_billid);
             TDbCommand.ExcSqlex(ls_sql,lQueryex);
           end;

           //累加结算单开票金额
           ls_sql := 'SELECT COUNT(EBH_AUTOIN) lcount FROM EXP_BILL_HEAD WHERE EBH_AUTOIN = ' + QuotedStr(ls_new_billid);
           lQuery := TDbCommand.OpenSql(ls_sql);
           li_count := 0;
           while not lQuery.Eof do
           begin
              li_count := lQuery.FieldByName('lcount').AsInteger;
              lQuery.Next;
           end;
           If li_count = 1 Then
           begin
             ls_sql := 'SELECT EBH_ALL_VALUTA - EBH_INV_VALUTA INV_AVAILABLE_VALUTA FROM EXP_BILL_HEAD WHERE EBH_AUTOIN = ' + QuotedStr(ls_new_billid);
             lQuery := TDbCommand.OpenSql(ls_sql);
             lf_inv_available_valuta := lQuery.FieldByName('INV_AVAILABLE_VALUTA').AsFloat;

             If lf_inv_available_valuta + lf_old_in_fee < lf_new_inv_fee Then
             begin
               Business.Forms.Dialogs.ShowMessage('累加结算单开票金额时出错:编号为' + ls_new_billid + '的结算单的已开票金额,超出结算金额。');
               SysUtils.Abort;
             end;

             If lf_inv_available_valuta + lf_old_in_fee - lf_new_inv_fee = 0 Then
             begin
               ls_bill_inv_status := '50';
             end
             Else
             begin
               ls_bill_inv_status := '40';
             end;

             ls_sql := 'UPDATE EXP_BILL_HEAD SET EBH_INV_VALUTA = EBH_INV_VALUTA + ' + floattostr(lf_new_inv_fee) +
                       ', EBH_STATUS = ' + QuotedStr(ls_bill_inv_status) + 'WHERE EBH_AUTOIN = ' + QuotedStr(ls_new_billid);
             TDbCommand.ExcSqlex(ls_sql,lQueryex);
           end
           Else
           begin
             Business.Forms.Dialogs.ShowMessage('累加结算单开票金额时出错:编号为' + ls_new_billid + '的结算单不存在,不可累加。');
             SysUtils.Abort;
             Exit;
           end;

         end;
         //插入
         TUpdateKind.ukInsert:
         begin
           ls_new_billid := lDeltaDataSet.FieldByName('EIBD_BILLID').AsString;
           lf_new_inv_fee := lDeltaDataSet.FieldByName('EIBDCstdTtl').AsFloat;
           //累加结算单开票金额
           ls_sql := 'SELECT COUNT(EBH_AUTOIN) lcount FROM EXP_BILL_HEAD WHERE EBH_AUTOIN = ' + QuotedStr(ls_new_billid);
           lQuery := TDbCommand.OpenSql(ls_sql);
           li_count := 0;

           while not lQuery.Eof do
           begin
              li_count := lQuery.FieldByName('lcount').AsInteger;
              lQuery.Next;
           end;
           If li_count = 1 Then
           begin
             ls_sql := 'SELECT EBH_ALL_VALUTA - EBH_INV_VALUTA INV_AVAILABLE_VALUTA FROM EXP_BILL_HEAD WHERE EBH_AUTOIN = ' + QuotedStr(ls_new_billid);
             lQuery := TDbCommand.OpenSql(ls_sql);
             lf_inv_available_valuta := lQuery.FieldByName('INV_AVAILABLE_VALUTA').AsFloat;

             If lf_inv_available_valuta < lf_new_inv_fee Then
             begin
               Business.Forms.Dialogs.ShowMessage('累加结算单开票金额时出错:编号为' + ls_new_billid + '的结算单的已开票金额,超出结算金额。');
               SysUtils.Abort;
             end;

             If lf_inv_available_valuta - lf_new_inv_fee = 0 Then
             begin
               ls_bill_inv_status := '50';
             end
             Else
             begin
               ls_bill_inv_status := '40';
             end;

             ls_sql := 'UPDATE EXP_BILL_HEAD SET EBH_INV_VALUTA = EBH_INV_VALUTA + ' + floattostr(lf_new_inv_fee) +
                       ', EBH_STATUS = ' + QuotedStr(ls_bill_inv_status) + 'WHERE EBH_AUTOIN = ' + QuotedStr(ls_new_billid);
             TDbCommand.ExcSqlex(ls_sql,lQueryex);
           end
           Else
           begin
             Business.Forms.Dialogs.ShowMessage('累加结算单开票金额时出错:编号为' + ls_new_billid + '的结算单不存在,不可累加1。');
             SysUtils.Abort;
             Exit;
           end;
         end;
         //删除
         TUpdateKind.ukDelete:
         begin
           ls_old_billid := lDeltaDataSet.FieldByName('EIBD_BILLID').AsString;
           lf_old_in_fee :=  lDeltaDataSet.FieldByName('EIBDCstdTtl').AsFloat;
           //恢复结算单开票金额
           ls_sql := 'SELECT COUNT(EBH_AUTOIN) lcount FROM EXP_BILL_HEAD WHERE EBH_AUTOIN = ' + QuotedStr(ls_old_billid);
           lQuery := TDbCommand.OpenSql(ls_sql);
           li_count := 0;
           while not lQuery.Eof do
           begin
              li_count := lQuery.FieldByName('lcount').AsInteger;
              lQuery.Next;
           end;
           If li_count = 1 Then
           begin
             ls_sql := 'SELECT EBH_INV_VALUTA INV_AVAILABLE_VALUTA FROM EXP_BILL_HEAD WHERE EBH_AUTOIN = ' + QuotedStr(ls_old_billid);
             lQuery := TDbCommand.OpenSql(ls_sql);
             lf_inv_available_valuta := lQuery.FieldByName('INV_AVAILABLE_VALUTA').AsFloat;

             If lf_inv_available_valuta < lf_old_in_fee Then
             begin
               Business.Forms.Dialogs.ShowMessage('恢复结算单开票金额时出错:编号为' + ls_old_billid + '的结算单的已开票金额,不够扣减2。');
               SysUtils.Abort;
             end;

             If lf_inv_available_valuta - lf_old_in_fee = 0 Then
             begin
               ls_bill_inv_status := '20';
             end
             Else
             begin
               ls_bill_inv_status := '40';
             end;

             ls_sql := 'UPDATE EXP_BILL_HEAD SET EBH_INV_VALUTA = EBH_INV_VALUTA - ' +  floattostr(lf_old_in_fee) +
                        ', EBH_STATUS = ' + QuotedStr(ls_bill_inv_status) + 'WHERE EBH_AUTOIN = ' + QuotedStr(ls_old_billid);
             TDbCommand.ExcSqlex(ls_sql,lQueryex);

           end;
         end;
       else
         //
       end;
       lDeltaDataSet.NextStatus;
     end;
   finally
     lDeltaDataSet.Free;
   end;
end;
回复 支持 反对

使用道具 举报

 楼主| 发表于 2008-3-3 13:19:52 | 显示全部楼层
lQueryex := TDbCommand.CreateConnect(DSB_INV_BILL_DETAIL.DataSet);
   lDeltaDataSet:= TDeltaDataSet.Create(DSB_INV_BILL_DETAIL.DataSet);
这些代码是把执行sql要用到的连接和数据集DSB_INV_BILL_DETAIL.DataSet的连接合并到同一个事务中
回复 支持 反对

使用道具 举报

发表于 2008-3-3 14:19:10 | 显示全部楼层
http://wiki.justep.cn/%E4%BA%8B%E5%8A%A1
楼主这个用法不能实现事务。必须把这些update放在外面,和dataset.appleupdate并列写才可以。
因为这个事件里写,dataset还没有启动事务。

在BeforeApplyUpdates事件中并没有启动事务,所以,楼主的代码并不能保证出入库表的数据和库存表的数据在一个事务中提交,不能保证数据的一致性,Delphi里也是一样的

“现在碰到的问题是如果前面有过更新了后面的更新语句就没有起到作用”楼主是跟踪执行了,还是看到数据不一致了
回复 支持 反对

使用道具 举报

 楼主| 发表于 2008-3-3 14:32:48 | 显示全部楼层
那么一般像这种情况,代码写在什么地方呢
回复 支持 反对

使用道具 举报

 楼主| 发表于 2008-3-3 14:34:18 | 显示全部楼层
跟踪执行,sql语句是执行的,但是执行的时候,说记录不存在,实际上该记录前面已经被更新过一次了
回复 支持 反对

使用道具 举报

发表于 2008-3-3 14:35:36 | 显示全部楼层
一般放在数据集外面执行。比如一个按钮,或者写成一个函数,在适当的地方触发。最好别在数据集事件上。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2008-3-3 14:36:11 | 显示全部楼层
所以最后显示的结果就是第一次更新的时候的结果,后面再执行的更新语句没有起到作用
回复 支持 反对

使用道具 举报

发表于 2008-3-3 14:39:49 | 显示全部楼层
您的代码非常长,大概意思就是  14楼写的。  您想实现的事务的效果,并不能完成。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2008-3-3 14:56:49 | 显示全部楼层
但是我实际跟踪下来确实是在一个事务中的,如果我代码执行的时候,sql语句报错,提交失败的话,数据集中的相关更新也没有进行
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Justep Inc.

GMT+8, 2025-7-9 23:14 , Processed in 0.041603 second(s), 13 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表