2010-05-05 10 views
7

Estamos utilizando SQLite en una aplicación multiproceso y multiproceso. Los archivos de la base de datos SQLite se cifran utilizando el cifrado SQLite incorporado. El FAQ establece que SQLite debe ser capaz de gestionar accesos a múltiples procesos utilizando el mecanismo de bloqueos. Estamos experimentando un problema extraño: Cuando muchos subprocesos acceden al mismo archivo de base de datos, algunas veces se producen infracciones de restricciones, más específicamente: un campo con una restricción única obtiene valores duplicados después de llamar a la instrucción "insertar o reemplazar". Sucede bastante a menudo ahora, que estamos usando la encriptación. Antes de comenzar a utilizar el cifrado SQLite, no notamos ese comportamiento. ¿Existen problemas conocidos específicos con esto?SQLite Acceso multiproceso

+0

SQLite indica que no se puede compartir el mismo objeto a través de subprocesos. ¿Estás seguro de que no lo haces? – Andrey

+0

@Andrey: ¿puedes publicar el enlace a esto? Cuando lo leí recientemente, SQLite dice que es seguro para subprocesos, * aunque * sienten que los hilos son malos y que no deberían usar SQLite en un programa multiproceso, a menos que solo se acceda por un hilo. Pero técnicamente, se supone que es seguro para subprocesos. Al menos, eso es lo que recuerdo haber leído. – Dave

+0

@Dave: http://www.sqlite.org/cvstrac/wiki?p=MultiThreading frase clave: con "threadsafe" queremos decir que puede usar diferentes conexiones de bases de datos SQLite en diferentes hilos al mismo tiempo. – Andrey

Respuesta

8

Mientras SQLite es "thread-safe" todavía no se puede modificar al mismo tiempo la base de datos:

Cada hilo luego procede a insertar un número de registros , digamos 1000. El problema que se encontrará es el siguiente: un hilo obtendrá el control sobre la base de datos al establecer un bloqueo en el archivo . Esto está bien, pero el resto de los hilos seguirá fallando por cada intento de INSERT mientras el bloqueo esté activo. (reference) está permitido

sólo un hilo de modificar la base de datos a la vez, pero puede tener múltiples hilos que intento de modificar la base de datos.

Si se quiere evitar el problema bloqueado defecto, mientras que puede comprobar la bandera SQLITE_BUSY:

prueba para SQLITE_BUSY, lo que hice no hacer originalmente. He aquí algunos pseudo-código para ilustrar una solución:

while (continueTrying) { 
    retval = sqlite_exec(db, sqlQuery, callback, 0, &msg); 
    switch (retval) { 
     case SQLITE_BUSY: 
     Log("[%s] SQLITE_BUSY: sleeping fow a while...", threadName); 
     sleep a bit... (use something like sleep(), for example) 
     break; 
     case SQLITE_OK: 
     continueTrying = NO; // We're done 
     break; 
     default: 
     Log("[%s] Can't execute \"%s\": %s\n", threadName, sqlQuery, msg); 
     continueTrying = NO; 
     break; 
    } 
    } 

    return retval; 

same reference

Mi apuesta es que su violación de la restricción no tiene nada que ver con múltiples hilos, por lo que podría por favor publicar la violación de restricción real que se está obteniendo (o un ejemplo que cumple con www.sscce.org).

0

Asegúrate de que no estás compartiendo conexiones a través de subprocesos; cada subproceso debe hacer su propia conexión. Y asegúrese de que está ajustando sus consultas en las transacciones.

Uso el contenedor de código abierto System.Data.Sqlite (http://sqlite.phxsoftware.com/) ADO.Net, que es seguro para subprocesos siempre que no comparta las conexiones entre subprocesos. También cifra fácilmente la base de datos, como se describe aquí: http://sqlite.phxsoftware.com/forums/t/130.aspx (simplemente configure la propiedad de la contraseña). Busque en su foro cómo utiliza específicamente Microsoft Crypto API para hacer el cifrado y para obtener más información sobre la seguridad de las secuencias.

2

Gracias por todos sus comentarios!

(hay que mencionar que estamos utilizando System.Data.SQLite.la biblioteca de red)

En el mientras tanto nos hizo algunas pruebas más y aquí están los resultados

===============

Hemos construido un probador que hace lo siguiente: - crea una tabla con varios campos. Uno de los campos - nvarchar (255) - tiene un índice único: "crea un índice único IX_MyKey en la tabla (MyKey)" - inicia muchos procesos idénticos (25) simultáneamente - Cada proceso tiene una clave (cadena que representa un número 1 25) - Cada proceso tiene un solo hilo (principal) haciendo lo siguiente en un bucle durante 30 segundos:

leer el registro donde MyKey = @ MyKey (la clave del proceso) obtener un valor de una campo numérico escribir de nuevo 'valor + 1' al mismo campo del mismo registro "poner o reemplazar ... donde MyKey MyKey = @"

===============

  • Cuando hacemos todo lo anterior usando la biblioteca System.Data.SQLite sin cifrado - todo funciona como se esperaba (incluyendo las cerraduras que están ralentizando el acceso a la base de datos cuando la cantidad de procesos aumenta)

  • cuando usamos cifrado (mediante el establecimiento de una contraseña para la base de datos), el índice de restricción único es "roto" - no aparecen registros que tienen el mismo valor MyKey

===============

Por lo tanto, las vetas del problema están de alguna manera relacionadas con el cifrado ...