2010-10-15 14 views
6

¿Existe un problema conocido con SQLite dando un error "la base de datos está bloqueada" para una segunda consulta en una sola transacción cuando se usa Perl DBD :: SQLite? Escenario: Linux, Perl DBI, AutoCommit => 0, una subrutina con dos bloques de código (utilizando los bloques para localizar nombres de variables). En el primer bloque de código, se crea un identificador de consulta mediante prepare() en una sentencia select, se ejecuta() y se cierra el bloque. El segundo bloque de código se crea otro identificador de consulta por preparación para una instrucción de actualización, y frecuentemente (30% del tiempo) SQLite/DBI da un error bloqueado en la base de datos en esta etapa. Creo que el error ocurre durante prepare() y no durante execute().¿Por qué SQLite da una "base de datos está bloqueada" para una segunda consulta en una transacción cuando se usa DBD :: SQLite de Perl?

Mi trabajo es confirmar después de la primera consulta. (Llamar al final de la primera consulta no ayudó). Prefiero no comprometerme por varias razones relacionadas con la elegancia y el rendimiento. El código original funcionó bien durante muchos años con Postgres como base de datos. Intenté sqlite_use_immediate_transaction sin ningún efecto.

En todas las demás situaciones, he encontrado que SQLite funciona muy bien, así que sospecho que esto es un descuido en el controlador DBD, en lugar de un problema con SQLite. Lamentablemente, mi código actual es una gran pila de scripts y módulos, por lo que no tengo un caso de prueba de un solo archivo corto.

+0

¿Puede mostrarnos su pequeño estuche de prueba que demuestra el problema? –

Respuesta

6

No relacionado con esto de todos modos es: Transaction and Database Locking del DBD::SQLite perldoc?

Transacción por AutoCommit o begin_work es agradable y práctico, pero a veces se puede conseguir un molesto "base de datos está bloqueado" error. Esto generalmente ocurre cuando alguien comienza una transacción e intenta escribir en una base de datos mientras otra persona lee desde la base de datos (en otra transacción). Puede que se sorprenda, pero SQLite no bloquea una base de datos cuando comienza una transacción normal (diferida) para maximizar la concurrencia. Reserva un bloqueo cuando emite una declaración para escribir, pero hasta que realmente intente escribir con una declaración de compromiso, permite que otras personas lean desde la base de datos. Sin embargo, la lectura desde la base de datos también requiere bloqueo compartido, y eso evita darle el bloqueo exclusivo que reservó, por lo que obtiene el error "la base de datos está bloqueada" y otras personas recibirán el mismo error si intentan escribir después, como usted todavía tiene un bloqueo pendiente. busy_timeout no ayuda en este caso.

Para evitar esto, establezca un tipo de transacción explícitamente. Puede emitir una transacción inmediata de inicio (o comenzar una transacción exclusiva) para cada transacción o establecer el atributo de identificador de base de datos sqlite_use_immediate_transaction en verdadero (desde 1.30_02) para usar siempre una transacción inmediata (incluso cuando simplemente usa begin_work o apaga AutoCommit). .

my $dbh = DBI->connect("dbi:SQLite::memory:", "", "", { 
    sqlite_use_immediate_transaction => 1, 
}); 

Tenga en cuenta que esto sólo funciona cuando todas las conexiones utilizan la misma transacción (no diferida). Ver http://sqlite.org/lockingv3.html para detalles de bloqueo.

Cuestiones relacionadas