visual studio microsoft español descargar community c# sqlite locking sqlite3 system.data.sqlite

c# - microsoft - visual studio installer



¿Cómo se realiza la consulta de SQLite con un lector de datos sin bloquear la base de datos? (2)

Use el modo WAL .

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".

La documentación de SQLite dice:

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

  1. Abra el archivo de la base de datos y obtenga un bloqueo COMPARTIDO.

La documentación además establece el bloqueo "COMPARTIDO":

La base de datos puede leerse pero no escribirse. 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.

Las preguntas frecuentes dicen:

Múltiples procesos pueden tener la misma base de datos abierta al mismo tiempo. Múltiples procesos pueden estar haciendo un SELECTO al mismo tiempo. Sin embargo, solo un proceso puede hacer cambios en la base de datos en cualquier momento.

El libro The Definitive Guide to SQLite afirma:

... una conexión puede elegir tener un nivel de aislamiento sin lectura mediante el pragma read_uncommited . Si se establece en verdadero , 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.

Intenté configurar el pragma para leer sin compromiso dentro de la instrucción de comando de consulta SQL de la siguiente manera:

PRAGMA read_uncommitted = 1; SELECT Column1, Column2 FROM MyTable

Una actualización de SQL en el mismo subproceso con una conexión diferente aún falló con la excepción "la base de datos está bloqueada". 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?

Actualizar:

Ambas respuestas a continuación funcionan. 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.


No pude hacer que esto funcione con el proveedor de datos de código abierto desde aquí . Sin embargo, pude hacer que esto funcione con 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 memoria caché compartida. Tenga en cuenta que esto solo debe ejecutarse una vez para todo el proceso; consulte la documentación de SQLite .

sqlite3_enable_shared_cache(1);

A continuación, prefija la instrucción de consulta SQL utilizada por el lector de datos con la instrucción pragma de la siguiente manera:

PRAGMA read_uncommitted = 1; SELECT Column1, Column2 FROM MyTable

Ahora se puede actualizar e insertar filas libremente mientras el lector de datos está activo. Puede encontrar documentación adicional de SQLite en la memoria caché compartida aquí .

Actualizar:

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

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

Uno puede configurar las lecturas no confirmadas 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();