¿Cómo desbloqueo una base de datos SQLite?


269
sqlite> DELETE FROM mails WHERE (`id` = 71);
SQL error: database is locked

¿Cómo desbloqueo la base de datos para que esto funcione?


Puede haber otro proceso para acceder al archivo de la base de datos. ¿Ha verificado lsof?
inexistente

Tuve el mismo problema, el problema estaba en el antivirus cuando lo desactivé, mi aplicación funciona bien, pero cuando la activo encuentro el error "la base de datos está bloqueada", espero que te ayude.
user8510915

Respuestas:


267

En Windows, puede probar este programa http://www.nirsoft.net/utils/opened_files_view.html para descubrir que el proceso está manejando el archivo db. Intenta cerrar ese programa para desbloquear la base de datos

En Linux y macOS puede hacer algo similar, por ejemplo, si su archivo bloqueado es development.db:

$ fuser development.db

Este comando mostrará qué proceso está bloqueando el archivo:

> desarrollo.db: 5430

Solo mata el proceso ...

matar -9 5430

... Y tu base de datos se desbloqueará.


19
... con la advertencia obvia de que necesitas saber lo que estás haciendo. Si es un proceso sin importancia, entonces killdebería estar bien, pero debe tener cuidado de matarlo correctamente, y kill -9probablemente sea incorrecto o excesivo. Si el proceso se cuelga y de lo contrario no morirá, a veces es necesario kill -9. ¡Pero no quiere ir y matar el trabajo de producción principal solo para poder informar que la base de datos ya no está bloqueada!
tripleee

La solución más simple sería simplemente reiniciar su computadora.
chacham15

77
@ chacham15: usted asume que la base de datos está en "mi" computadora e ignora la posibilidad de que se ejecuten muchos procesos importantes en la misma computadora que la que tiene la base de datos bloqueada. La solución "más simple" nunca es tan simple;)
tzot

1
@KyleCarlson - sqlite y mysql son fundamentalmente diferentes en ese aspecto. No hay nada particularmente malo con SQLite-db-browser.
Berry Tsakala

66
Esta solución supone que hay un proceso que bloquea el archivo. Es posible que un proceso se bloquee dejando el archivo SQLite en un estado inutilizable. En ese caso, mira mi respuesta.
robert

90

Hice que mi sqlite db se bloqueara al bloquear una aplicación durante una escritura. Así es como lo arreglé:

echo ".dump" | sqlite old.db | sqlite new.db

Tomado de: http://random.kakaopor.hu/how-to-repair-an-sqlite-database


44
sqlite3:sqlite> .dump PRAGMA foreign_keys=OFF; BEGIN TRANSACTION; /**** ERROR: (5) database is locked *****/ ROLLBACK; -- due to errors
woky

No funciona paraFOREIGN KEY constraint failed (RELEASE RESTOREPOINT)
gies0r

52

La página DatabaseIsLocked que se enumera a continuación ya no está disponible. La página de bloqueo y concurrencia de archivos describe los cambios relacionados con el bloqueo de archivos introducidos en v3 y pueden ser útiles para futuros lectores. https://www.sqlite.org/lockingv3.html

La página SQLite wiki DatabaseIsLocked ofrece una buena explicación de este mensaje de error. Establece, en parte, que la fuente de contención es interna (al proceso que emite el error).

Lo que esta página no explica es cómo SQLite decide que algo en su proceso tiene un bloqueo y qué condiciones podrían conducir a un falso positivo.


2
El problema es que la página es incorrecta o está desactualizada: tengo un proceso que literalmente no hace más que un solo INSERT que recibe ese mensaje bloqueado: no es posible que este proceso haya causado el bloqueo. El problema estaba en otro proceso hablando con el mismo DB.
Dan Jameson

44
@ converter42 Enlace roto.
Ole Tange

32

Eliminar el archivo -journal suena como una idea terrible. Está ahí para permitir que sqlite revierta la base de datos a un estado consistente después de un bloqueo. Si lo elimina mientras la base de datos está en un estado inconsistente, entonces queda una base de datos corrupta. Citando una página del sitio sqlite :

Si se produce un bloqueo o una pérdida de energía y se deja un diario activo en el disco, es esencial que el archivo de base de datos original y el diario dinámico permanezcan en el disco con sus nombres originales hasta que otro proceso SQLite abra el archivo de la base de datos y lo revierta . [...]

Sospechamos que un modo de falla común para la recuperación de SQLite ocurre así: se produce una falla de energía. Una vez que se restablece la energía, un usuario o administrador del sistema bien intencionado comienza a buscar daños en el disco. Ven su archivo de base de datos llamado "important.data". Este archivo quizás les sea familiar. Pero después del accidente, también hay un diario caliente llamado "important.data-journal". Luego, el usuario elimina el diario activo, pensando que está ayudando a limpiar el sistema. No conocemos otra forma de prevenir esto que no sea la educación del usuario.

Se supone que la reversión sucederá automáticamente la próxima vez que se abra la base de datos, pero fallará si el proceso no puede bloquear la base de datos. Como han dicho otros, una posible razón para esto es que otro proceso actualmente lo tiene abierto. Otra posibilidad es un bloqueo NFS obsoleto, si la base de datos está en un volumen NFS. En ese caso, una solución alternativa es reemplazar el archivo de la base de datos con una copia nueva que no esté bloqueada en el servidor NFS (mv database.db original.db; cp original.db database.db). Tenga en cuenta que las preguntas frecuentes de sqlite recomiendan precaución con respecto al acceso concurrente a bases de datos en volúmenes NFS, debido a implementaciones defectuosas del bloqueo de archivos NFS.

No puedo explicar por qué eliminar un archivo -journal le permitiría bloquear una base de datos que antes no podía. ¿Es eso reproducible?

Por cierto, la presencia de un archivo -journal no necesariamente significa que hubo un bloqueo o que hay cambios para revertir. Sqlite tiene algunos modos de diario diferentes, y en los modos PERSIST o TRUNCATE deja siempre el archivo de diario en su lugar y cambia el contenido para indicar si hay o no transacciones parciales para revertir.


23

Si desea eliminar el error "la base de datos está bloqueada", siga estos pasos:

  1. Copie su archivo de base de datos a otra ubicación.
  2. Reemplace la base de datos con la base de datos copiada. Esto desreferenciará todos los procesos que estaban accediendo a su archivo de base de datos.

2
Intenté 'fuser <DB>' como se describió anteriormente, pero no funcionó. Estos simples pasos funcionan para mí.
Jackie Yeh

En mi caso, también tuve que reiniciar mi Jupyter Notebook.
Victor

15

Si un proceso tiene un bloqueo en una base de datos SQLite y se bloquea, la base de datos permanece bloqueada permanentemente. Ese es el problema. No es que algún otro proceso tenga un bloqueo.


48
Entonces, ¿cómo desbloquear el DB?
Erik Kaplun

44
Esto simplemente no es cierto. El sistema operativo mantiene los bloqueos. Lee la respuesta a continuación.
JJ

13

los archivos SQLite db son solo archivos, por lo que el primer paso sería asegurarse de que no sea de solo lectura. La otra cosa que debe hacer es asegurarse de que no tiene algún tipo de visor de GUI SQLite DB con el DB abierto. Puede tener la base de datos abierta en otro shell, o su código puede tener la base de datos abierta. Por lo general, vería esto si un subproceso diferente o una aplicación como el Navegador de base de datos SQLite tiene la base de datos abierta para escribir.


44
En mi experiencia, SQLite Database Browser (SDB) bloquea de forma reproducible una base de datos si edita datos con ella pero luego no la guarda en SDB. Si lo guarda, libera el bloqueo.
Chelonian

Puedo insertar pero no puedo eliminar.
Wennie

10

Tuve este problema hace un momento, usando una base de datos SQLite en un servidor remoto, almacenado en un soporte NFS. SQLite no pudo obtener un bloqueo después de que la sesión de shell remota que utilicé se bloqueó mientras la base de datos estaba abierta.

Las recetas de recuperación sugeridas anteriormente no funcionaron para mí (incluida la idea de mover primero y luego copiar la base de datos). Pero después de copiarlo en un sistema que no es NFS, la base de datos se volvió utilizable y no parece que se hayan perdido datos.


9

Mi bloqueo fue causado por el bloqueo del sistema y no por un proceso de bloqueo. Para resolver esto, simplemente cambié el nombre del archivo y luego lo volví a copiar a su nombre y ubicación originales.

Usando un shell de Linux que sería ...

mv mydata.db temp.db
cp temp.db mydata.db

solución muy fácil, resolviendo mi problema de una base de datos bloqueada en una unidad de red.
Maverick2805


4

Encontré que la documentación de los diversos estados de bloqueo en SQLite es muy útil. Michael, si puedes realizar lecturas pero no puedes realizar escrituras en la base de datos, eso significa que un proceso ha obtenido un bloqueo RESERVADO en tu base de datos pero aún no ha ejecutado la escritura. Si está utilizando SQLite3, hay un nuevo bloqueo llamado PENDIENTE en el que no se permiten más procesos para conectarse, pero las conexiones existentes pueden realizar lecturas, por lo que si este es el problema, debería considerarlo.


4

Este error puede aparecer si el archivo está en una carpeta remota, como una carpeta compartida. Cambié la base de datos a un directorio local y funcionó perfectamente.


3

Tengo ese problema dentro de la aplicación, que accede a SQLite desde 2 conexiones: una era de solo lectura y la segunda para escribir y leer. Parece que esa conexión de solo lectura bloqueó la escritura desde la segunda conexión. Finalmente, resulta que se requiere finalizar o, al menos, restablecer las declaraciones preparadas INMEDIATAMENTE después del uso. Hasta que se abra la declaración preparada, la base de datos se bloqueó para escritura.

NO OLVIDES LA LLAMADA:

sqlite_reset(xxx);

o

sqlite_finalize(xxx);

3

Algunas funciones, como INDEX, pueden tomar mucho tiempo, y bloquea toda la base de datos mientras se ejecuta. En casos como ese, ¡es posible que ni siquiera use el archivo de diario!

Entonces, la mejor / única forma de verificar si su base de datos está bloqueada porque un proceso le está escribiendo ACTIVAMENTE (y, por lo tanto, debe dejarla en paz hasta que se complete su operación) es md5 (o md5sum en algunos sistemas) el archivo dos veces . Si obtiene una suma de comprobación diferente, la base de datos se está escribiendo, y realmente REALMENTE no desea eliminar -9 ese proceso porque puede terminar fácilmente con una tabla / base de datos corrupta si lo hace.

Reitero, porque es importante, la solución NO es encontrar el programa de bloqueo y matarlo, es encontrar si la base de datos tiene un bloqueo de escritura por una buena razón, y continuar desde allí. A veces la solución correcta es solo un descanso para tomar café.

La única forma de crear esta situación de bloqueo pero no estar escrito es si su programa se ejecuta BEGIN EXCLUSIVE, porque quería hacer algunas alteraciones en la tabla o algo así, por cualquier motivo nunca envía un mensaje ENDposterior y el proceso nunca termina . Las tres condiciones que se cumplen son muy poco probables en cualquier código escrito correctamente, y como tal 99 de cada 100 veces cuando alguien quiere matar -9 su proceso de bloqueo, el proceso de bloqueo en realidad está bloqueando su base de datos por una buena razón. Los programadores generalmente no agregan la BEGIN EXCLUSIVEcondición a menos que realmente lo necesiten, porque evita la concurrencia y aumenta las quejas de los usuarios. SQLite solo lo agrega cuando realmente lo necesita (como cuando se indexa).

Finalmente, el estado 'bloqueado' no existe DENTRO del archivo, como han indicado varias respuestas, reside en el núcleo del sistema operativo. El proceso que se ejecutó BEGIN EXCLUSIVEha solicitado al sistema operativo que se coloque un bloqueo en el archivo. ¡Incluso si su proceso exclusivo se ha bloqueado, su sistema operativo podrá determinar si debe mantener el bloqueo de archivos o no! ¡No es posible terminar con una base de datos que está bloqueada, pero ningún proceso la bloquea activamente! Cuando se trata de ver qué proceso está bloqueando el archivo, generalmente es mejor usar lsof en lugar de fusor (esta es una buena demostración de por qué: /unix/94316/fuser-vs-lsof- para verificar archivos en uso ). Alternativamente, si tiene DTrace (OSX) puede usar iosnoop en el archivo.


2

Simplemente me sucedió algo similar: mi aplicación web pudo leer de la base de datos, pero no pudo realizar ninguna inserción o actualización. Un reinicio de Apache resolvió el problema al menos temporalmente.

Sin embargo, sería bueno poder rastrear la causa raíz.


2

El comando lsof en mi entorno Linux me ayudó a descubrir que se estaba bloqueando un proceso manteniendo abierto el archivo.
Mató el proceso y se resolvió el problema.



2

Debería ser el problema interno de una base de datos ...
Para mí, se ha manifestado después de intentar explorar la base de datos con el "Administrador de SQLite" ...
Entonces, si no puede encontrar otro proceso, conéctese a la base de datos y simplemente no puede solucionarlo, solo prueba esta solución radical:

  1. Proporcione para exportar sus tablas (puede usar el "Administrador de SQLite" en Firefox)
  2. Si la migración altera su esquema de base de datos, elimine la última migración fallida
  3. Cambie el nombre de su archivo "database.sqlite"
  4. Ejecute "rake db: migrate" para crear una nueva base de datos de trabajo
  5. Proporcionar para otorgar los permisos correctos a la base de datos para la importación de tablas
  6. Importa tus tablas respaldadas
  7. Escribe la nueva migración
  8. Ejecútelo con " rake db:migrate"

1

Me encontré con este mismo problema en Mac OS X 10.5.7 ejecutando scripts de Python desde una sesión de terminal. Aunque había detenido las secuencias de comandos y la ventana de terminal estaba en el símbolo del sistema, daría este error la próxima vez que se ejecute. La solución fue cerrar la ventana del terminal y luego volver a abrirla. No tiene sentido para mí, pero funcionó.


1

Acabo de tener el mismo error. Después de 5 minets google-ing descubrí que no había cerrado un shell que estaba usando el db. Solo ciérrelo e intente nuevamente;)


1

Yo tuve el mismo problema. Aparentemente, la función de reversión parece sobrescribir el archivo db con el diario, que es el mismo que el archivo db pero sin el cambio más reciente. He implementado esto en mi código a continuación y ha estado funcionando bien desde entonces, mientras que antes mi código simplemente se quedaba bloqueado mientras la base de datos permanecía bloqueada.

Espero que esto ayude

mi código de python

##############
#### Defs ####
##############
def conn_exec( connection , cursor , cmd_str ):
    done        = False
    try_count   = 0.0
    while not done:
        try:
            cursor.execute( cmd_str )
            done = True
        except sqlite.IntegrityError:
            # Ignore this error because it means the item already exists in the database
            done = True
        except Exception, error:
            if try_count%60.0 == 0.0:       # print error every minute
                print "\t" , "Error executing command" , cmd_str
                print "Message:" , error

            if try_count%120.0 == 0.0:      # if waited for 2 miutes, roll back
                print "Forcing Unlock"
                connection.rollback()

            time.sleep(0.05)    
            try_count += 0.05


def conn_comit( connection ):
    done        = False
    try_count   = 0.0
    while not done:
        try:
            connection.commit()
            done = True
        except sqlite.IntegrityError:
            # Ignore this error because it means the item already exists in the database
            done = True
        except Exception, error:
            if try_count%60.0 == 0.0:       # print error every minute
                print "\t" , "Error executing command" , cmd_str
                print "Message:" , error

            if try_count%120.0 == 0.0:      # if waited for 2 miutes, roll back
                print "Forcing Unlock"
                connection.rollback()

            time.sleep(0.05)    
            try_count += 0.05       




##################
#### Run Code ####
##################
connection = sqlite.connect( db_path )
cursor = connection.cursor()
# Create tables if database does not exist
conn_exec( connection , cursor , '''CREATE TABLE IF NOT EXISTS fix (path TEXT PRIMARY KEY);''')
conn_exec( connection , cursor , '''CREATE TABLE IF NOT EXISTS tx (path TEXT PRIMARY KEY);''')
conn_exec( connection , cursor , '''CREATE TABLE IF NOT EXISTS completed (fix DATE, tx DATE);''')
conn_comit( connection )

1

Una razón común para obtener esta excepción es cuando intenta realizar una operación de escritura mientras mantiene recursos para una operación de lectura. Por ejemplo, si SELECCIONA de una tabla y luego intenta ACTUALIZAR algo que ha seleccionado sin cerrar su ResultSet primero.


1

También tenía errores de "la base de datos está bloqueada" en una aplicación multiproceso, que parece ser el código de resultado SQLITE_BUSY , y lo resolví estableciendo sqlite3_busy_timeout en algo adecuadamente largo como 30000.

(En una nota al margen, ¡qué extraño que en una pregunta de 7 años ya nadie lo haya descubierto! SQLite realmente es un proyecto peculiar y sorprendente ...)


1

Antes de pasar a la opción de reinicio, vale la pena ver si puede encontrar el usuario de la base de datos sqlite.

En Linux, se puede emplear fuserpara este fin:

$ fuser database.db

$ fuser database.db-journal

En mi caso obtuve la siguiente respuesta:

philip    3556  4700  0 10:24 pts/3    00:00:01 /usr/bin/python manage.py shell

Lo que demostró que tenía otro programa de Python con pid 3556 (manage.py) usando la base de datos.


1

Una vieja pregunta, con muchas respuestas, aquí están los pasos que he seguido recientemente leyendo las respuestas anteriores, pero en mi caso el problema se debió al intercambio de recursos cifs. Este caso no se informó anteriormente, así que espero que ayude a alguien.

  • Verifique que no haya conexiones abiertas en su código Java.
  • Verifique que ningún otro proceso esté utilizando su archivo db SQLite con lsof.
  • Verifique que el propietario del usuario de su proceso jvm en ejecución tenga permisos r / w sobre el archivo.
  • Intente forzar el modo de bloqueo en la apertura de la conexión con

    final SQLiteConfig config = new SQLiteConfig();
    
    config.setReadOnly(false);
    
    config.setLockingMode(LockingMode.NORMAL);
    
    connection = DriverManager.getConnection(url, config.toProperties());

Si está utilizando su archivo SQLite db sobre una carpeta compartida NFS, verifique este punto de las preguntas frecuentes de SQLite y revise las opciones de configuración de montaje para asegurarse de evitar bloqueos, como se describe aquí :

//myserver /mymount cifs username=*****,password=*****,iocharset=utf8,sec=ntlm,file,nolock,file_mode=0700,dir_mode=0700,uid=0500,gid=0500 0 0

1

Obtuve este error en un escenario un poco diferente de los que se describen aquí.

La base de datos SQLite descansaba en un sistema de archivos NFS compartido por 3 servidores. En 2 de los servidores pude ejecutar consultas en la base de datos con éxito, en el tercero pensé que recibía el mensaje "la base de datos está bloqueada".

Lo que sucedió con esta tercera máquina fue que no le quedaba espacio /var. Cada vez que intenté ejecutar una consulta en CUALQUIER base de datos SQLite ubicada en este sistema de archivos recibí el mensaje "la base de datos está bloqueada" y también este error en los registros:

8 de agosto 10:33:38 kernel server01: lockd: no se puede monitorear 172.22.84.87

Y este también:

8 de agosto 10:33:38 server01 rpc.statd [7430]: Error al insertar: escribiendo /var/lib/nfs/statd/sm/other.server.name.com: No queda espacio en el dispositivo 8 de agosto 10:33: 38 server01 rpc.statd [7430]: STAT_FAIL al servidor01 para SM_MON de 172.22.84.87

Después de manejar la situación espacial, todo volvió a la normalidad.


1

Si está intentando desbloquear la base de datos de Chrome para verla con SQLite , simplemente cierre Chrome.

Ventanas

%userprofile%\Local Settings\Application Data\Google\Chrome\User Data\Default\Web Data

or

%userprofile%\Local Settings\Application Data\Google\Chrome\User Data\Default\Chrome Web Data

Mac

~/Library/Application Support/Google/Chrome/Default/Web Data

0

De tus comentarios anteriores dijiste que había un archivo de diario.

Esto podría significar que ha abierto una transacción (¿EXCLUSIVA?) Y aún no ha confirmado los datos. ¿Su programa o algún otro proceso dejó atrás el diario?

Reiniciar el proceso sqlite mirará el archivo de diario y limpiará cualquier acción no confirmada y eliminará el archivo de diario.


0

Como dijo Seun Osewa, a veces un proceso zombie se sentará en la terminal con un bloqueo adquirido, incluso si no lo crees posible. Su secuencia de comandos se ejecuta, se bloquea y vuelve a la solicitud, pero hay un proceso zombie generado en algún lugar por una llamada a la biblioteca, y ese proceso tiene el bloqueo.

Cerrar el terminal en el que estabas (en OSX) podría funcionar. Reiniciar funcionará. Puede buscar procesos "python" (por ejemplo) que no estén haciendo nada y matarlos.


0

puedes probar esto: .timeout 100para establecer el tiempo de espera. No sé qué sucede en la línea de comandos, pero en C # .Net cuando hago esto: "UPDATE table-name SET column-name = value;"obtengo que la base de datos está bloqueada, pero esto "UPDATE table-name SET column-name = value"funciona bien.

Parece que cuando agrega;, sqlite buscará más comandos.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.