1

我正在使用 Delphi IBQuery 和 IBTransaction 组件使用此查询更新数据库中的所有记录:

UPDATE INVOICES SET BLK = 0;

当用户打开另一个客户端应用程序时,它会在某些记录(由用户打开)上留下死锁。

问题在于我的应用程序必须完成上述查询。

是否可以实施某种解决方案来强制消除死锁?例如 SQL 查询?

Firebird 版本是 2.1.2.18118 在 Windows 7 上运行

4

2 回答 2

6

最好的选择是重构这些应用程序。

FB/IB 的自然模式是有两个并行事务。

  • #1将是只读的、已提交的、永不关闭的,它仅用于读取数据。

  • #2将在短时间内打开/提交以实际应用更改。任何“正在编辑”的数据本身都不会开启交易。

长期编辑事务通过阻止垃圾收集并强制它(和索引)包含大量虚假数据来影响数据库。

我不知道您是否可以通过 IBX + IBQuery + 某种自定义更新查询(例如 TUpdateSQL 在 bDE 时代)来做到这一点。第 3 方 FB 连接库通常对双向事务模式有一些支持。

然而,这种方法强加了一个非常具体的应用程序设计模式,并使 Firebird 无法保证数据一致性——这现在是应用程序的负担。评论带来了一个很好的链接: Re: [firebird-support] Long read-only Transactions


在现代 Firebird 中,如果您具有数据库管理员/所有者角色,您可以强制删除事务。阅读有关监控表的信息。请注意,2.5.1 中存在错误,因此您可能会等待 2.5.2 发布。

但是,如果您强制回滚这些事务 - 应用程序将如何表现?用户仍然会在编辑时突然发现他的大部分更改都丢失了。

PS。http://www.sql.ru/forum/actualthread.aspx?tid=910920此代码用于mon$transactions将事务映射到连接,然后强行断开有问题的应用程序。如果直接delete from mon$transactions where...不可用,那么这将是剩下的选项。

聚苯乙烯。由于 FB 2.1 长时间事务最好每隔几分钟提交(并关闭)一次(甚至是 r/o 事务)。原因是如果他们碰巧使用 BLOB 计算,这可能会导致数据库无法控制的增长,只有在事务关闭时才会重置。虽然这可能会触发所有 db-aware 控件的重新读取,但在没有像 MIDAS ClientDataset 这样的中间缓存的情况下使用事务,这可以说仍然比数据库膨胀更好,在一些极少数情况下报告非常快。

于 2012-10-09T10:25:32.020 回答
0

我已经设法通过一些用户交互来解决问题。

首先,我正在检查用户是否正在编辑任何发票。

SELECT COUNT(*) FROM MON$RECORD_STATS WHERE MON$STAT_GROUP = 2 AND MON$RECORD_UPDATES <> 0

然后,如果在上述查询执行过程中发现任何锁,我将向用户显示一条消息“请关闭所有打开的发票...”,并创建一个failed.sql文件,其中包含必须执行的查询,以防万一如果用户只是终止我的应用程序。

在下一次启动我的应用程序时,我检查failed.sql文件是否存在并尝试使用死锁检查再次执行它。

所以我的应用程序对用户来说变得有点烦人,但它不会做出任何可能给用户带来挫败感的无人看管的操作。

于 2012-10-10T03:13:08.470 回答