Question

I'm using Delphi IBQuery and IBTransaction components to update all records in database with this query:

UPDATE INVOICES SET BLK = 0;

When users leave another client application opened it leaves deadlock on some records (opened by users).

The problem is with my application that must complete the query above.

Is it possible to implement some kind of solution to forcebly remove deadlocks? For example an SQL query?

Firebird version is 2.1.2.18118 running on Windows 7

Was it helpful?

Solution

Best option would be to refactor those applications.

Natural mode for FB/IB would be to have two parallel transactions.

  • #1 would be read-only read-committed, never-closing, it would be only used for reading data.

  • #2 would be opened/committed with short bursts to actually apply changes. Any data "in editing" would not be opening transaction per se.

Long-living editing transaction are affecting database by blocking garbage collection and forcing it (and indices) to contain lot of bogus data.

I dunno if you can do this via IBX + IBQuery + some kind of custom update queries like TUpdateSQL was in bDE times. 3rd-party FB connection libs usually have some support for bi-transactional mode.

This approach however imposes a very specific pattern of how your application should be designed and makes Firebird unable to warrant data consistency - this is now your application's burden. The comments brought a nice link about it: Re: [firebird-support] Long read-only Transactions


In modern Firebird you can forcibly drop transactions, if you have database admin/owner role. Read about Monitoring tables. Note that there were bugs in 2.5.1 so you'd probably wait for 2.5.2 release.

However if you'd forcibly rollback those transaction - how would applications behave ? the user would still be editing just to suddenly discover most of his changes were lost.

PS. http://www.sql.ru/forum/actualthread.aspx?tid=910920 this code uses mon$transactions to map transaction to connection and then forcibly disconnects offending application. If direct delete from mon$transactions where... would not be available, then that would be the option left.

PPS. Since FB 2.1 long-time transactions should better be committed (and closed) each few minutes (even r/o ones). The reason is if they would happen to use BLOB calculations that may lead to uncontrollable grow of the database only reset by transactions closing. While this might trigger re=reading of all the db-aware controls, working with the transaction without intermediate caching like MIDAS ClientDataset, that is arguably still better than database inflation, that in some rare cases reported to be very fast.

OTHER TIPS

I've managed to decide the problem with a bit of user interaction.

First, I'm checking whether any of the invoices are being edited by users.

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

Then, if there are any locks found during the above query execution I'm showing a message to user "Please close all opened invoices...", and I create a failed.sql file with the query that has to be executed in case if user just terminates my application.

On the next launch of my application, I check whether the failed.sql file exists and try to execute it again with deadlock check.

So my app became a bit more annoying to user, but it doesn't make any unattended actions that can bring frustration to users.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top