2011-03-20 11 views
10

Estoy usando System.Data.Sqlite para acceder a la base de datos SQLite en C#. Tengo una consulta que debe leer las filas en una tabla. Al recorrer las filas y mientras el lector está abierto, se deben realizar ciertas actualizaciones de SQL. Me encuentro con una excepción de "base de datos está bloqueada".¿Cómo se realiza la consulta de SQLite con un lector de datos sin bloquear la base de datos?

Los SQLite documentation estados:

Cuando un proceso quiere leer desde un archivo de base de datos, siguieron la siguiente secuencia de pasos:

  1. Abrir el archivo de base de datos y obtener un bloqueo compartido. más

La documentación indica sobre "compartida" de bloqueo:

La base de datos se puede leer, pero no escribir. Cualquier cantidad de procesos puede contener bloqueos COMPARTIDOS al mismo tiempo, por lo tanto, puede haber muchos lectores simultáneos. Pero ningún otro hilo o proceso puede escribir en el archivo de base de datos mientras uno o más bloqueos COMPARTIDOS estén activos.

Los FAQ estados:

procesos múltiples pueden tener la misma base de datos abiertos al mismo tiempo. Múltiples procesos pueden estar haciendo un SELECTO al mismo tiempo. Pero solo un proceso puede hacer cambios en la base de datos en cualquier momento en el tiempo.

El libro The Definitive Guide to SQLite estados:

... una conexión puede optar por tener un nivel de aislamiento de lectura no confirmada utilizando el read_uncommited pragma. Si está configurado en true, la conexión no colocará bloqueos de lectura en las tablas que lee. Por lo tanto, otro escritor puede cambiar una tabla, ya que la conexión en el modo de lectura no confirmada no puede bloquear ni ser bloqueada por ninguna otra conexión.

que intentaron establecer el pragma para leer no comprometidos dentro de la instrucción comando de consulta SQL de la siguiente manera:

PRAGMA read_uncommitted = 1; 
SELECT Column1, Column2 FROM MyTable 

Una actualización SQL en el mismo hilo usando una conexión diferente aún no con una "base de datos está bloqueado "excepción" Luego intenté establecer el nivel de aislamiento para leer sin compromiso en la instancia de conexión. Todavía no hay cambio con la misma excepción.

¿Cómo puedo lograr que un lector de datos abierto recorra las filas de la base de datos sin bloquear la base de datos, de modo que pueda ejecutar las actualizaciones?

Actualización:

Ambas respuestas a continuación el trabajo. Sin embargo, desde entonces me he alejado del uso del diario de reversión predeterminado hasta ahora utilizando el registro de escritura anticipada, que proporciona una mayor concurrencia de las lecturas y escrituras de la base de datos.

Respuesta

8

Utilice el modo WAL.

+0

estoy usando ADO.Net. De acuerdo con http://sqlite.phxsoftware.com/, la versión de System.Data.SQLite.dll es 1.0.66.0 Apr 18, 2010 y la versión de SQLite es 3.6.23.1. Parece que necesito la versión 3.7+ para utilizar WAL. ¿Alguna sugerencia? ¿Hay un proveedor actualizado de ADO.Net? – Elan

+0

Sí, consulte http://system.data.sqlite.org/index.html/doc/trunk/www/index.wiki la versión 1.0.68.0 de febrero de 2011 es una fusión de código con SQLite 3.7.5 –

+0

Parece prometedor; desafortunadamente, no vi nada listo ni disponible para descargar todavía ... ¿Está oficialmente disponible el lanzamiento que mencionas 1.0.68.0 o es un alfa/beta? – Elan

2

No pude hacer que esto funcione con el proveedor de datos de código abierto here. Sin embargo, pude hacer que esto funcione usando la versión estándar gratuita de dotConnect de la siguiente manera:

Cree la importación de DLL a continuación, para que podamos habilitar la memoria caché compartida para SQLite.

[DllImport("sqlite3.dll", CallingConvention = CallingConvention.Cdecl)] 
public static extern int sqlite3_enable_shared_cache(int enable); 

Ejecute la función anterior para habilitar la caché compartida. Tenga en cuenta que esto solo debe ejecutarse una vez para todo el proceso; consulte SQLite documentation.

sqlite3_enable_shared_cache(1); 

Entonces prefijo de la instrucción de consulta SQL utilizada por el lector de datos con la declaración pragma de la siguiente manera:

PRAGMA read_uncommitted = 1; 
SELECT Column1, Column2 FROM MyTable 

ahora se puede actualizar libremente e insertar filas, mientras que el lector de datos está activo. Se puede encontrar documentación SQLite adicional en la memoria caché compartida here.

Actualización:

Una versión más reciente del proveedor de datos SQLite Devart ahora es compatible con esta de una manera mejorada. Para habilitar la memoria caché compartida se puede hacer la siguiente llamada:

Devart.Data.SQLite.SQLiteConnection.EnableSharedCache(); 

Uno puede configurar los no comprometidos lee en la cadena de conexión, por ejemplo, de la siguiente manera:

Devart.Data.SQLite.SQLiteConnectionStringBuilder builder = new SQLiteConnectionStringBuilder(); 
builder.ReadUncommitted = true; 
builder.DateTimeFormat = Devart.Data.SQLite.SQLiteDateFormats.Ticks; 
builder.DataSource = DatabaseFilePath; 
builder.DefaultCommandTimeout = 300; 
builder.MinPoolSize = 0; 
builder.MaxPoolSize = 100; 
builder.Pooling = true; 
builder.FailIfMissing = false; 
builder.LegacyFileFormat = false; 
builder.JournalMode = JournalMode.Default; 
string connectionString = builder.ToString(); 
Cuestiones relacionadas