如何使Firebird客户端应用程序等待行解锁

时间:2015-05-21 16:48:25

标签: delphi firebird interbase dbexpress

我熟悉使用ADO(dbGo)的Microsoft SQL服务器世界,我为该环境编写了许多应用程序。现在我有一个遗留的Delphi 7应用程序和Firebird 2.5数据库,我必须维护它。

但我发现如果2个客户端应用程序执行此操作:

SQLQuery.SQL.Text := 'Update mytable set field1 = 11 where keyfield = 99'
SQLQuery.Execute;

在几乎完全相同的时间,第二个应用程序得到一个"死锁"立即出错。在SQL Server中,将有一个等待期

ADOConnection.Isolationlevel = ilCursorstability;
ADOConnection.CommandTimeout := 5;

在第二个客户端应用程序中引发任何异常之前。异常处理可能涉及在批处理过程中被视为非常不寻常的情况的回滚。这是合理的。 5秒是计算机处理时间非常长的时间。

现在,我在Firebird客户端使用相同方法的尝试没有结果,因为"死锁" (实际上,正在使用的记录)会立即发生。

如果数据库引擎无法配置等待一些条件来改进(记录锁定要发布),那么现在责任必须由客户端应用程序开发人员负责,他们必须编写疯狂的慢代码来克服出现的问题让我成为Firebird的主要失败者。

一旦"僵局"已经检测到,除了断开连接组件

之外,条件不会被清除
while rowsupdated = 0 and counter < 5 do
begin
  try
    rowsupdated := SQLQuery.Execute;
  except
    SQLConnection.Connected := False;
    SQLConnection.Connected := True;
  end;
  Inc(Counter)
end;

如果在Firebird中使用DBX中的DBX没有任何实质性的锁定容差,如何使用强大的多用户表更新客户端?

3 个答案:

答案 0 :(得分:7)

客户端可以指定事务是否应该等待死锁解析。如果在您的情况下立即发生死锁,可能是因为您的配置(在客户端上使用nowait事务参数)。不使用nowait将导致服务器端检测到死锁,并且(在可配置的超时之后)在客户端上引发异常。

Firebird 2.0开始,您还可以从客户端指定事务的锁定超时,从而覆盖服务器配置的超时值。

答案 1 :(得分:3)

可以将Firebird事务配置为nowait或wait(具有或不具有特定超时)。如何配置取决于驱动程序,因为我不熟悉Delphi我不能评论。 Nowait通常是默认值,因为在大多数情况下等待只会延迟不可避免的事情。

“死锁”错误有点用词不当,因为它不是正常并发白话中的死锁。错误的第二部分通常更具描述性,例如更新与并发更新的冲突。,它是一个历史性工件,它被归为“死锁”(尽管在大多数情况下,这些错误意味着您需要重启你的交易,所以在这个意义上它是“死”)。

答案 2 :(得分:0)

我正在使用“回答你自己的问题”按钮。我发现了一个解决方案。

  1. 为Firebird / Interbase安装 IBPhoenix opensource ODBC驱动程序
  2. 将ODBC DSN配置为连接到Firebird.fdb并关闭nowait,并按秒将LockTimeout设置为必需。我选择了15秒。
  3. 使用Delphi 7 ADO(dbGo)TADOConnection配置为使用Microsoft OLE DB Provider for ODBC驱动程序。
  4. 这是重要的一点:将ADOConnection.TransactionIsolation设置为ilReadUncommited或ilDirtyRead。
  5. 这样做会导致TADOQuery.ExecSQL实际上等待(最多达到指定的15秒),如果它发现该记录已在尚未提交的事务中更新或者回滚!

    这与在这种情况下立即引发所谓的“死锁”异常的DBX驱动程序不同。 (如上所述)

    所以,如果两个查询都这样做

    Update MYTABLE set NUM = NUM + 1 where keyvalue = 99;
    

    并且起始值(在任何更新之前)为0,两个事务提交后的NUM值都是2,正如预期的那样。

    从NUM = 0开始。如果第一个事务回滚,则第二个事务可以提交(或回滚)。并且第二次更新提交后的值仅为1.

    我不知道它是如何或为什么这么好用,特别是因为Firebird不应该支持ReadUnComitted或DirtyRead,但我很高兴它按照我想要的方式工作。