Utilisé NuGet package: System.Data.SQLite.Core, 1.0.98.1Pooled connexion en lecture seule SQLite est utilisé pour un accès en lecture-écriture
Problème: Dans mon programme, j'utilise SQLite avec mise en commun activé et lecture seule accès dans certains cas. Normalement, il fonctionne très bien, mais s'il y a beaucoup de mélange en lecture seule/lecture-écriture des demandes intensives à base de données, puis échoue programme à l'exception suivante:
Unhandled Exception: System.Data.SQLite.SQLiteException: attempt to write a readonly database
attempt to write a readonly database
at System.Data.SQLite.SQLite3.Reset(SQLiteStatement stmt)
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(CommandBehavior behavior)
at System.Data.SQLite.SQLiteCommand.ExecuteNonQuery()
Si je désactive la mise en commun, le programme fonctionne très bien . Je suppose que la connexion en lecture seule regroupée est utilisée pour la connexion en lecture-écriture. Est-ce que quelque chose me manque? Est-ce que c'est un comportement attendu ou non?
Code minimum à reproduire (échec à INSERT ou DELETE). Si j'introduis du retard, par exemple Thread.Sleep(10000)
, cela fonctionne très bien. Si je supprime la boucle, cela fonctionne aussi bien.
const string DbFilePath = "test.sqlite";
string readOnlyConnectionString = new SQLiteConnectionStringBuilder
{
DataSource = DbFilePath,
Pooling = true,
ReadOnly = true
}.ConnectionString; // data source=test.sqlite;pooling=True;read only=True
string readWriteConnectionString = new SQLiteConnectionStringBuilder
{
DataSource = DbFilePath,
Pooling = true,
ReadOnly = false
}.ConnectionString; // data source=test.sqlite;pooling=True;read only=False
File.Delete(DbFilePath);
using (SQLiteConnection conn = new SQLiteConnection(readWriteConnectionString))
using (SQLiteCommand cmd = new SQLiteCommand("CREATE TABLE items(id INTEGER NOT NULL PRIMARY KEY)", conn))
{
conn.Open();
cmd.ExecuteNonQuery();
}
while (true) // <= if we comment the loop, the program executes without error
{
using (SQLiteConnection conn = new SQLiteConnection(readWriteConnectionString))
using (SQLiteCommand cmd = new SQLiteCommand("INSERT INTO items(id) VALUES (1)", conn))
{
conn.Open();
cmd.ExecuteNonQuery();
}
using (SQLiteConnection conn = new SQLiteConnection(readOnlyConnectionString))
using (SQLiteCommand cmd = new SQLiteCommand("SELECT COUNT(*) FROM items", conn))
{
conn.Open();
cmd.ExecuteScalar();
}
using (SQLiteConnection conn = new SQLiteConnection(readWriteConnectionString))
using (SQLiteCommand cmd = new SQLiteCommand("DELETE FROM items", conn))
{
conn.Open();
cmd.ExecuteNonQuery();
}
}
Avez-vous examiné ces connexions pour vous assurer qu'elles sont effectivement différentes? Le fichier est-il réellement inscriptible sur le disque? –
@ LasseV.Karlsen Les chaînes de connexion sont différentes. Le fichier est lisible et accessible en écriture. Comme je l'ai dit, si je désactive la mise en commun, ou si j'introduis un retard artificiel, le programme fonctionne bien. –
Cela ressemble à un bogue, une faille de conception ou peut-être même une décision de conception dans la classe SQLiteConnectionPool. A en juger par un coup d'oeil rapide à la source ([SQLiteConnectionPool] (https://system.data.sqlite.org/index.html/artifact/aec6733a2d48e3d2)) il semble qu'il ne considère que le nom de fichier, et non la chaîne de connexion entière. –