I've very little experience with databases and have run in to a problem with a trigger causing a deadlock in a firebird 2.5 database.
There is two tables in the database . When items are added or removed from the ITEMS table a Trigger updates STATS.ITEMCOUNT & STATS.SIZE. There are 4 triggers in total 2 Incrementing & and two decrementing.
The stats table has a single row and is used to track what in the database. Am I doing this the wrong way? And If not is there a work round.
A deadlock occurs within the first few minutes of starting the application.
UPDATE1: Posted all triggers.
UPDATE2: Posted ExecuteNonQuery Method
UPDATE3: Deadlocks still occur even when using the view method kindly suggested by pilcrow. In fact I even tried using a stored procedure which deadlocked again. Wrapping the select statement in a transaction also failed because the Firebird Ado provider does not support parallel transactions.
public void ExecuteNonQuery(string NonQuery)
{
try
{
FbCommand FBC = new FbCommand(NonQuery, DBConnection);
FBC.ExecuteNonQuery();
FBC.Dispose();
}
catch (FbException e)
{
Log.FatalException("Database NonQuery Error", e);
}
}
}
Database
** Tables **
CREATE TABLE ITEMS (
ID ID NOT NULL /* ID = VARCHAR(36) NOT NULL */,
EXPIRYTIME EXPIRYTIME NOT NULL /* EXPIRYTIME = BIGINT NOT NULL */,
ITEMSIZE ITEMSIZE /* ITEMSIZE = BIGINT NOT NULL */,
ACCESSCOUNT ACCESSCOUNT DEFAULT 1 NOT NULL /* ACCESSCOUNT = INTEGER DEFAULT 1 NOT NULL */,
LASTACCESSTIME LASTACCESSTIME /* LASTACCESSTIME = TIMESTAMP NOT NULL */
);
CREATE TABLE STATS (
INSTANCE SMALLINT,
SIZE BIGINT DEFAULT 0,
ITEMCOUNT BIGINT DEFAULT 0,
HITS BIGINT DEFAULT 0,
MISSES BIGINT DEFAULT 0
);
** Triggers **
/* Trigger: TRG_INCREMENT_ITEMCOUNT_STATS */
CREATE OR ALTER TRIGGER TRG_INCREMENT_ITEMCOUNT_STATS FOR ITEMS
ACTIVE AFTER INSERT POSITION 1
AS
begin
UPDATE STATS SET ITEMCOUNT = ITEMCOUNT + 1 WHERE INSTANCE = '0';
end
/* Trigger: TRG_DECREMENT_ITEMCOUNT_STATS */
CREATE OR ALTER TRIGGER TRG_DECREMENT_ITEMCOUNT_STATS FOR ITEMS
ACTIVE AFTER DELETE POSITION 2
AS
begin
UPDATE STATS SET ITEMCOUNT = ITEMCOUNT - 1 WHERE INSTANCE = '0';
end
/* Trigger: TRG_INCREMENT_HITS_STATS */
CREATE OR ALTER TRIGGER TRG_INCREMENT_HITS_STATS FOR ITEMS
ACTIVE AFTER UPDATE POSITION 3
AS
begin
UPDATE STATS SET HITS = HITS + 1 WHERE INSTANCE = '0';
end
/* Trigger: TRG_INCREMENT_SIZE_STATS */
CREATE OR ALTER TRIGGER TRG_INCREMENT_SIZE_STATS FOR ITEMS
ACTIVE AFTER INSERT POSITION 4
AS
BEGIN
UPDATE STATS SET SIZE = SIZE + NEW.ITEMSIZE WHERE INSTANCE = 0;
END
/* Trigger: TRG_DECREMENT_CACHESIZE_STATS */
CREATE OR ALTER TRIGGER TRG_DECREMENT_CACHESIZE_STATS FOR ITEMS
ACTIVE AFTER DELETE POSITION 5
AS
BEGIN
UPDATE STATS SET SIZE = SIZE - OLD.ITEMSIZE WHERE INSTANCE = 0;
END
Fixed by using
.IsolationLevel = IsolationLevel.ReadUncommitted;
in the connection string.