首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >并发控制

并发控制
EN

Stack Overflow用户
提问于 2011-03-10 22:08:11
回答 3查看 1.6K关注 0票数 7

你好

我想知道在3层应用程序中实现并发控制的最佳方法?首先可以想到的是:

  1. 客户端希望从数据集中编辑记录。
  2. 向服务器发送请求,请求该记录的锁定。
  3. 服务器接受/拒绝基于锁表的编辑请求。

基于这种情况,锁应该同时引用使用该记录锁定的记录和客户端。

客户端必须定期向服务器发送保持活动的消息。“保持活着”用于释放锁定的记录,以防客户在编辑操作中丢失。

我将使用Delphi与数据with。也许这是一个新手的问题,但我必须问!

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2011-03-11 00:27:04

我正在基于jachguate的乐观并发控制答案来回答在评论中提出的一个问题。

我更喜欢尽可能地使用OCC,因为实现更容易。我将讨论使用对象持久化框架的三层应用程序。我的预测方案有三个层次:

  1. 行或对象级控件,其中在每个对象上存储唯一的版本ID。如果您试图更新对象,则会自动更改版本id。如果您的版本id与已经存在的版本不匹配,则更新失败。
  2. 字段或列级别锁定。发送原始对象和更新对象的完整副本。在应用新值之前,更新中的每个字段都有实际值和旧值。要求用户解决冲突而不是放弃冲突是可能的,但是随着提交中数据量的增加,冲突变得非常混乱。
  3. 悲观锁定。每个对象都有一个锁所有者,通常为null (对象未被锁定)。当您想要编辑对象时,首先锁定它。这里的问题是,需要整理锁,而周围的业务规则可能很难看(需要什么超时)。

这的优点是,大多数情况下,低成本的OCC路径是采取的。对于经常发生的事情,但在低争论的情况下,好处是重大的。想一想仓库中的产品跟踪--产品总是在移动,但很少同时移动相同的项目,当它们同时移动时,解决问题很容易(剩余的数量=原始的减去我的删除和您的删除)。对于产品被重新定位的复杂情况,在产品运输过程中锁定产品可能是有意义的(因为这反映了实际情况)。

当您必须回到锁定状态时,能够通知两个用户并拥有一个通信通道通常是有用的。当锁可用时,至少通知想要锁的用户,最好允许他们向锁持有人发送消息,甚至可能允许他们强制锁。然后通知锁输家“乔·史密斯拿走了你的锁,你失去了你的改变”。让办公室政治来解决这一问题:)

我通常通过用户投诉来驱动回退过程,而不是通过错误报告。如果用户抱怨他们在某一特定过程中经常丢失编辑,请更改它。如果用户抱怨记录锁定得太频繁,您将不得不重构您的对象映射,以增加锁定粒度或进行业务流程更改。

票数 3
EN

Stack Overflow用户

发布于 2011-03-10 23:01:56

我设计我的应用程序时考虑到了一个乐观并发控制,在用户想要编辑它时没有锁定任何记录,也没有试图控制并发性。

重要的计算和更新是在服务器端(应用程序或数据库)在处理客户端应用的更新时设置适当的内置数据库锁定功能之后完成的。DataSnap自动事务回滚防止这些锁在发生故障时阻止其他并发用户。

使用DataSnap,您可以通过为您的字段适当使用ProviderFlags来防止两个用户编辑冲突时的数据丢失。为要自动检查的任何字段设置pfInWhere,使其在编辑/删除时具有与读取记录相同的值。

此外,当冲突发生时,您可以在Application (提供程序OnUpdateError事件)、客户端(TClientDataSet OnReconcileError事件)或甚至要求用户进行适当的冲突解决(查看新项存储库中的ReconcileErrorDialog )时进行编程反应。

同时,IMHO避免了维护锁列表、客户列表、每个客户端列表的锁、保持活跃的消息、健壮的应用程序服务器故障恢复以及所有可能出现的故障--您将以更干净和更好的解决方案结束--所需的复杂性。

票数 3
EN

Stack Overflow用户

发布于 2011-03-10 23:27:13

千斤顶给出的方法很好,而且可能更好,但是如果您确实想实现这个方法,您将需要在服务启动时在服务器上创建一个TThreadList。使用TThreadList,因为它是线程安全的。您可以在每个表上设置TThreadList,以便将导航列表的性能影响降到最低。要控制锁定的内容,需要创建一个对象并将其传递给列表

代码语言:javascript
复制
  TLockedItem = class(TObject)
  public
    iPK: Integer;
    iClientID: Integer;
  end;

要执行实际的锁定,您需要这样的操作:

代码语言:javascript
复制
function LockItem(pPK, pClientID: Integer): Boolean;
var
  oLockedItem: TLockedItem;
  oInternalList: TList;
  iCont: Integer;
  bExists: Boolean;
begin
  bExists := False;
  if (Assigned(oLockedList)) then
  begin
    oInternalList := oLockedList.LockList;
    try
      if (oInternalList.Count > 0) then
      begin
        iCont := 0;
        while ((not bExists) and (iCont < oInternalList.Count)) do
        begin
          oLockedItem := TLockedItem(oInternalList[iCont]);
          if (oLockedItem.iPK = pPk) then
            bExists := True
          else
            Inc(iCont);
        end;
      end;
    finally
      oLockedList.UnlockList;
    end;
    if (not bExists) then
    begin
      oLockedItem := TLockedItem.Create;
      oLockedItem.iPK := pPK;
      oLockedItem.iClientID := pClientID;
      oInternalList := oLockedList.LockList;
      try
        oInternalList.Add(oLockedItem);
      finally
        oLockedList.UnlockList;
      end;
    end;
  end;
  Result := bExists;
end;

这只是你所需要的一个想法。您必须使用类似的逻辑来执行解锁方法。您可能需要一个客户端列表,该列表将保留每个客户端持有的每个TLockItem的点,以防失去连接。这不是一个明确的答案,只是一个方向上的推动,以防你想要实现这个方法。

祝好运

票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/5266514

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档