SQL Server 2008 R2中不同客户端更新同一记录

发布于 2024-12-08 18:47:52 字数 3137 浏览 3 评论 0原文

在此处输入图像描述

我正在网络模式下使用 SQL Server 2008 R2 在 Delphi-2010 中开发应用程序。

我的问题是,在某些情况下,多个客户端打开同一条记录进行更新。
第一个客户端可以更新记录,但其他客户端则不能,因为 SQL SERVER 无法找到有问题的记录,因为它已被修改。应用程序应允许这 2 次更新而不通知客户端。

该表包含许多字段,并且客户端可以更新其中的任何字段,因为不使用 SQL 语句并且使用 UPDATEBATCH()。

// Press UPDATE
procedure TarticleEditForm.saveButtonClick(Sender: TObject);
begin
 if (articleCode.Text <> '') AND (counter.Text <> '') AND (articleLabel.Text <> '') AND      (tbCombo.Text <> '') AND (griffeCombo.Text <> '') then begin
      ADOArticleFind.SQL.Text := 'SELECT * FROM article WHERE ID<>''' + ADOArticle.FieldByName('ID').Value + ''' AND article=''' + articleCode.Text + ''' AND mode=''' + modeCombo.Text + ''' AND counter=''' + counter.Text + '''';
      ADOArticleFind.Open;
      // UPDATE
      if ADOArticleFind.RecordCount = 0 then begin
           // SET Date Modification
           ADOArticle.FieldByName('dateModification').Value := Now;
           ADOArticle.FieldByName('modifiePar').Value := mainForm.user;
           ADOArticle.UpdateBatch();
           // Update ArticleColor/ArticleTissu tables
           ADOArticleColor.SQL.Text := 'UPDATE articleColor SET article=''' + articleCode.Text + ''', mode=''' + modeCombo.Text + ''', counter=''' + counter.Text + ''' WHERE article=''' + tmpArticleCode + ''' AND mode=''' + tmpMode + ''' AND counter=''' + tmpCounter + '''';
           ADOArticleColor.ExecSQL;
           ADOArticleTissu.SQL.Text := 'UPDATE articleTissu SET article=''' + articleCode.Text + ''', mode=''' + modeCombo.Text + ''', counter=''' + counter.Text + ''' WHERE article=''' + tmpArticleCode + ''' AND mode=''' + tmpMode + ''' AND counter=''' + tmpCounter + '''';
           ADOArticleTissu.ExecSQL;
           // create event log
           mainForm.ADOUser.SQL.Text := 'SELECT * FROM users WHERE online=1 AND editArticleEvent=1 AND username<>''' + mainForm.user + '''';
           mainForm.ADOUser.Open;
           while not mainForm.ADOUser.Recordset.EOF do begin
                mainForm.ADOMainEventLog.Insert;
                mainForm.ADOMainEventLog.FieldByName('event').Value := 'Article modifié: ' + designationCombo.Text + ' ' + saisonCombo.Text + ' ' + articleCode.Text + '-' + modeCombo.Text + counter.Text + ' de ' + griffeCombo.Text;
                mainForm.ADOMainEventLog.FieldByName('eventFrom').Value := mainForm.user;
                mainForm.ADOMainEventLog.FieldByName('eventTo').Value := mainForm.ADOUser.FieldByName('username').Value;
                mainForm.ADOMainEventLog.FieldByName('eventType').Value := 'editArticleEvent';
                mainForm.ADOMainEventLog.UpdateBatch();
                mainForm.ADOUser.Next;
           end;
           // Finish
           Self.Close;
      end
      else begin
           MessageBox(Application.Handle, 'Cet article existe déja.', 'GET© Driver', MB_ICONWARNING);
           articleCode.SetFocus;
      end;
 end
 else
      MessageBox(Application.Handle, 'Champs obligatoire(s) manquant(s).', 'GET© Driver', MB_ICONWARNING);
end;

enter image description here

I am developing an application in Delphi-2010 using SQL Server 2008 R2 in network Mode.

My problem is that in certain cases, multiple clients open the same record for update.
The first client can update the record but the others can't because SQL SERVER can't find the record in question because it has been modified. The application should allow the 2 updates without informing the client.

The table contains many fields nd' the client can update anyone of it for that am not using SQL statement nd' am using UPDATEBATCH().

// Press UPDATE
procedure TarticleEditForm.saveButtonClick(Sender: TObject);
begin
 if (articleCode.Text <> '') AND (counter.Text <> '') AND (articleLabel.Text <> '') AND      (tbCombo.Text <> '') AND (griffeCombo.Text <> '') then begin
      ADOArticleFind.SQL.Text := 'SELECT * FROM article WHERE ID<>''' + ADOArticle.FieldByName('ID').Value + ''' AND article=''' + articleCode.Text + ''' AND mode=''' + modeCombo.Text + ''' AND counter=''' + counter.Text + '''';
      ADOArticleFind.Open;
      // UPDATE
      if ADOArticleFind.RecordCount = 0 then begin
           // SET Date Modification
           ADOArticle.FieldByName('dateModification').Value := Now;
           ADOArticle.FieldByName('modifiePar').Value := mainForm.user;
           ADOArticle.UpdateBatch();
           // Update ArticleColor/ArticleTissu tables
           ADOArticleColor.SQL.Text := 'UPDATE articleColor SET article=''' + articleCode.Text + ''', mode=''' + modeCombo.Text + ''', counter=''' + counter.Text + ''' WHERE article=''' + tmpArticleCode + ''' AND mode=''' + tmpMode + ''' AND counter=''' + tmpCounter + '''';
           ADOArticleColor.ExecSQL;
           ADOArticleTissu.SQL.Text := 'UPDATE articleTissu SET article=''' + articleCode.Text + ''', mode=''' + modeCombo.Text + ''', counter=''' + counter.Text + ''' WHERE article=''' + tmpArticleCode + ''' AND mode=''' + tmpMode + ''' AND counter=''' + tmpCounter + '''';
           ADOArticleTissu.ExecSQL;
           // create event log
           mainForm.ADOUser.SQL.Text := 'SELECT * FROM users WHERE online=1 AND editArticleEvent=1 AND username<>''' + mainForm.user + '''';
           mainForm.ADOUser.Open;
           while not mainForm.ADOUser.Recordset.EOF do begin
                mainForm.ADOMainEventLog.Insert;
                mainForm.ADOMainEventLog.FieldByName('event').Value := 'Article modifié: ' + designationCombo.Text + ' ' + saisonCombo.Text + ' ' + articleCode.Text + '-' + modeCombo.Text + counter.Text + ' de ' + griffeCombo.Text;
                mainForm.ADOMainEventLog.FieldByName('eventFrom').Value := mainForm.user;
                mainForm.ADOMainEventLog.FieldByName('eventTo').Value := mainForm.ADOUser.FieldByName('username').Value;
                mainForm.ADOMainEventLog.FieldByName('eventType').Value := 'editArticleEvent';
                mainForm.ADOMainEventLog.UpdateBatch();
                mainForm.ADOUser.Next;
           end;
           // Finish
           Self.Close;
      end
      else begin
           MessageBox(Application.Handle, 'Cet article existe déja.', 'GET© Driver', MB_ICONWARNING);
           articleCode.SetFocus;
      end;
 end
 else
      MessageBox(Application.Handle, 'Champs obligatoire(s) manquant(s).', 'GET© Driver', MB_ICONWARNING);
end;

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

毁我热情 2024-12-15 18:47:52

我总是更喜欢使用纯 SQL 来在数据库中进行操作,而不是依赖数据集/表中的数据库抽象。

Query1.SQL.Text:= 'UPDATE table1 SET a=:newvalue WHERE A=:oldvalue';
Query1.ParamByName('newvalue').AsString:= '1';
Query1.ParamByName('oldvalue').AsString:= '2';
Query1.Prepare;
Query1.ExecSQL;

使用这样的代码,您可以根据需要对 SQL 服务器设置任意数量的并发更新。

I always prefer to use pure SQL to make stuff happen in databases, instead of relying on the database-abstraction in the datasets/tables.

Query1.SQL.Text:= 'UPDATE table1 SET a=:newvalue WHERE A=:oldvalue';
Query1.ParamByName('newvalue').AsString:= '1';
Query1.ParamByName('oldvalue').AsString:= '2';
Query1.Prepare;
Query1.ExecSQL;

Using code like this you can set as many concurrent updates to SQL-server as you'd like.

会傲 2024-12-15 18:47:52

既然您说您使用 updatebatch,我假设您使用 TADODataSet(或者可能是 TADOTable、TADOQuery)。

ADO 如何构建更新语句由记录集属性Update Criteria 控制。默认值为 adCriteriaUpdCols,这意味着更新的 where 子句会将所有修改的字段与旧/原始值进行比较。要使 updatebatch 仅使用关键列,您可以执行以下操作。

ADODataSet1.CommandText := 'select * from SomeTable';

ADODataSet1.Open;
ADODataSet1.Recordset.Properties['Update Criteria'].Value := adCriteriaKey;

ADODataSet1.Edit;
ADODataSet1.FieldByName('SomeColumn').AsString := 'New value';
ADODataSet1.Post;

ADODataSet1.UpdateBatch();

上面的 TADOQuery 代码如下所示。

ADOQuery1.SQL.Text := 'select * from SomeTable';

ADOQuery1.Open;
ADOQuery1.Recordset.Properties['Update Criteria'].Value := adCriteriaKey;

ADOQuery1.Edit;
ADOQuery1.FieldByName('SomeTable').AsString := 'New value';
ADOQuery1.Post;

ADOQuery1.UpdateBatch();

顺便说一句,adCriteriaKey 是在 ADOInt.pas 中定义的

Since you say that you use updatebatch I assume that you use TADODataSet (or perhaps TADOTable, TADOQuery).

How ADO builds the update statement is controlled by the recordset property Update Criteria. Default value is adCriteriaUpdCols which means that the update's where clause compares all modified fields against the old/original value. To make updatebatch only use the key columns you can do something like this.

ADODataSet1.CommandText := 'select * from SomeTable';

ADODataSet1.Open;
ADODataSet1.Recordset.Properties['Update Criteria'].Value := adCriteriaKey;

ADODataSet1.Edit;
ADODataSet1.FieldByName('SomeColumn').AsString := 'New value';
ADODataSet1.Post;

ADODataSet1.UpdateBatch();

The above code for a TADOQuery would look like this.

ADOQuery1.SQL.Text := 'select * from SomeTable';

ADOQuery1.Open;
ADOQuery1.Recordset.Properties['Update Criteria'].Value := adCriteriaKey;

ADOQuery1.Edit;
ADOQuery1.FieldByName('SomeTable').AsString := 'New value';
ADOQuery1.Post;

ADOQuery1.UpdateBatch();

BTW, adCriteriaKey is defined in ADOInt.pas

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文