SQLite: Multiple Connections to one file - the one

2019-08-28 13:18发布

问题:

We are using the System.Data.SQLite Wrapper in Version 1.0.80. Using this to establish multiple connections to a single SQLite database will show a weird behaviour.

We ensure having just one writable connection and multiple read-only connections.

When the first established connection is a read-only connection (using the connection string parameter Read Only=true) the second connection (which is writable due to missing read-only parameter) does not persist changes. There are no exceptions thrown either. If we turn it around, so we first establish write access and the read-only connection later, persisting changes is not a problem.

The problem is, in our code we cannot ensure which connection to a SQLite database file is used first and using multiple write connections lead to deadlock situations.

Does somebody know about this bug? Is there a workaround available?

Some source code:

private static void Test() {
    string fileFullPath = "\\Flash\\test.db";
    IDbConnection readCon = new SQLiteConnection(@"Data Source=" + fileFullPath + ";Read Only=true");
    readCon.Open();
    using (IDbCommand cmd = readCon.CreateCommand())
    {
        cmd.CommandText = "PRAGMA synchronous=OFF";
        cmd.ExecuteNonQuery();
    }
    using (IDbCommand cmd = readCon.CreateCommand())
    {
        cmd.CommandText = "PRAGMA journal_mode=OFF";
        cmd.ExecuteNonQuery();
    }
    using (IDbCommand cmd = readCon.CreateCommand())
    {
        cmd.CommandText = "SELECT * FROM tbltest WHERE foo = 'bar'";
        Console.WriteLine(cmd.ExecuteReader().Read());// FALSE as expected
    }
    // readcon still open
    // open a writable connection
    IDbConnection con = new SQLiteConnection(@"Data Source=" + fileFullPath);
    con.Open();
    using (IDbCommand cmd = con.CreateCommand())
    {
        cmd.CommandText = "PRAGMA synchronous=OFF";
        cmd.ExecuteNonQuery();
    }
    using (IDbCommand cmd = con.CreateCommand())
    {
        cmd.CommandText = "PRAGMA journal_mode=OFF";
        cmd.ExecuteNonQuery();
    }
    IDbTransaction transaction = con.BeginTransaction();
    using (IDbCommand cmd = con.CreateCommand())
    {
        cmd.CommandText = "INSERT INTO tbltest(foo) values('bar')";
        cmd.ExecuteNonQuery();
    }
    transaction.Commit();// persisting occurs here
    using (IDbCommand cmd = readCon.CreateCommand())
    {
        cmd.CommandText = "SELECT * FROM tbltest WHERE foo = 'bar'";
        Console.WriteLine(cmd.ExecuteReader().Read());// TRUE as expected
    }
    con.Close();
    readCon.Close();

    // verify writing
    readCon = new SQLiteConnection(@"Data Source=" + fileFullPath + ";Read Only=true");
    readCon.Open();
    using (IDbCommand cmd = readCon.CreateCommand())
    {
        cmd.CommandText = "SELECT * FROM tbltest WHERE foo = 'bar'";
        Console.WriteLine(cmd.ExecuteReader().Read()); // TRUE expected but we get FALSE
    }
    readCon.Close();
}

Output:

FALSE
TRUE
FALSE

Thanks for your help, schibbl