Search code examples
c#.netsqliteado.netsystem.data.sqlite

SQLite Database Locked exception


I am getting Database is locked exception from SQLite for some queries only.

Below is my code: When I execute any select statement it works fine.
When I am executing any write statement on Jobs Table it also works fine.

This works fine:

ExecuteNonQuery("DELETE FROM Jobs WHERE id=1");

But the same way if I am executing queries for Employees table it is throwing an exception that database is locked.
This throws Exception:

ExecuteNonQuery("DELETE FROM Employees WHERE id=1");

Below are my functions:

public bool OpenConnection()
{
    if (Con == null)
    {
        Con = new SQLiteConnection(ConnectionString);
    }
    if (Con.State == ConnectionState.Closed)
    {
        Con.Open();
        //Cmd = new SQLiteCommand("PRAGMA FOREIGN_KEYS=ON", Con);
        //Cmd.ExecuteNonQuery();
        //Cmd.Dispose();
        //Cmd=null;
        return true;
    }
    if (IsConnectionBusy())
    {
        Msg.Log(new Exception("Connection busy"));
    }
    return false;
}

public Boolean CloseConnection()
{
    if (Con != null && Con.State == ConnectionState.Open)
    {
        if (Cmd != null) Cmd.Dispose();
        Cmd = null;
        Con.Close();
        return true;
    }

    return false;
}

public Boolean ExecuteNonQuery(string sql)
{
    if (sql == null) return false;
    try
    {
        if (!OpenConnection())
            return false;
        else
        {
            //Tx = Con.BeginTransaction(IsolationLevel.ReadCommitted);
            Cmd = new SQLiteCommand(sql, Con);
            Cmd.ExecuteNonQuery();
            //Tx.Commit();
            return true;
        }
    }
    catch (Exception exception)
    {
        //Tx.Rollback();
        Msg.Log(exception);
        return false;
    }
    finally
    {
        CloseConnection();
    }
}

This is the Exception: At line 103 : Cmd.ExecuteNonQuery();

Exception Found: Type: System.Data.SQLite.SQLiteException Message: database is locked database is locked Source: System.Data.SQLite

Stacktrace: at System.Data.SQLite.SQLite3.Step(SQLiteStatement stmt) at System.Data.SQLite.SQLiteDataReader.NextResult() at System.Data.SQLite.SQLiteDataReader..ctor(SQLiteCommand cmd, CommandBehavior behave) at System.Data.SQLite.SQLiteCommand.ExecuteReader(CommandBehavior behavior) at System.Data.SQLite.SQLiteCommand.ExecuteNonQuery() at TimeSheet6.DbOp.ExecuteNonQuery(String sql) in d:\Projects\C# Applications\Completed Projects\TimeSheet6\TimeSheet6\DbOp.cs:line 103


Solution

  • Somewhere along the way a connection is getting left open. Get rid of OpenConnection and CloseConnection and change ExecuteNonQuery to this:

    using (SQLiteConnection c = new SQLiteConnection(ConnectionString))
    {
        c.Open();
        using (SQLiteCommand cmd = new SQLiteCommand(sql, c))
        {
            cmd.ExecuteNonQuery();
        }
    }
    

    Further, change the way you read data to this:

    using (SQLiteConnection c = new SQLiteConnection(ConnectionString))
    {
        c.Open();
        using (SQLiteCommand cmd = new SQLiteCommand(sql, c))
        {
            using (SQLiteDataReader rdr = cmd.ExecuteReader())
            {
                ...
            }
        }
    }
    

    Do not attempt, to manage connection pooling on your own like you are here. First, it's much more complex than what you have coded, but second, it's handled already inside the SQLiteConnection object. Finally, if you're not leveraging using, you're not disposing these objects properly and you end up with issues like what you're seeing now.