はじめに
SQLite は、ディスク上のデータベースファイルへのアクセスをファイルレベルのロックで管理しています。「database is locked」エラーは、あるプロセスがデータベースに書き込んでいる最中に、別のプロセスがアクセスしようとしたときに発生します。この状況は、次のようなさまざまな場面で起こり得ます。
- 複数のアプリケーションが同時にデータベースにアクセスしている。
- 長時間実行されるトランザクションが速やかにコミットまたはロールバックされない。
- データベース接続やカーソルが適切に扱われていない。
ヒント:
"database is locked"のような SQLite のエラーを調査するときは、データベースを視覚的に開いて確認すると役立ちます。Beekeeper Studio のようなデスクトップ SQL クライアントを使えば、
.dbファイルを開いてテーブルを閲覧し、クエリを対話的に再実行して変更が正しく反映されているかを確認できます。
エラーの解決方法
解決策 1: トランザクションを適切に管理する
トランザクションの扱いが不適切だと、データベースがロックされる原因になりがちです。必要に応じてコミットまたはロールバックを行い、トランザクションを速やかに完了させましょう。
例:
BEGIN TRANSACTION;
-- Insert data into the table
INSERT INTO employees (name, position) VALUES ('John Doe', 'Software Engineer');
-- Commit the transaction
COMMIT;
期待される出力:
出力はありませんが、トランザクションはデータベースをロックすることなく正常に完了します。
コミット後は、データベースが新しい書き込みを受け付けることを確認するのがおすすめです。
下のスクリーンショットは、Beekeeper Studio で同様の確認を行った例です。INSERT の後に SELECT を実行し、新しいデータ(この例では「Maria Lopez」のレコード)が正常に書き込まれたことを確認しています。

解決策 2: データベース接続を適切に使用する
操作が完了したら、必ずデータベース接続を適切に閉じましょう。これにより、データベースが不必要にロックされるのを防げます。
例:
import sqlite3
from contextlib import closing
database_path = 'mydatabase.db'
with closing(sqlite3.connect(database_path)) as conn:
with closing(conn.cursor()) as cursor:
cursor.execute("INSERT INTO employees (name, position) VALUES (?, ?)", ('Jane Doe', 'Project Manager'))
conn.commit()
期待される出力:
出力はありませんが、挿入操作はデータベースをロックすることなく実行され、接続も適切に閉じられます。
コードより GUI を使いたい場合、Beekeeper Studio はクエリを実行するたびに SQLite 接続を自動で開閉するため、データベースがロックされたままになるリスクを減らせます。
解決策 3: タイムアウトを設定する
複数のアクセスが想定される場合は、タイムアウト時間を設定すると効果的です。これにより、SQLite が「database is locked」エラーを返すまでの待機時間が決まり、ロックが解放される猶予が生まれます。
例:
import sqlite3
conn = sqlite3.connect('mydatabase.db', timeout=10.0) # Set timeout to 10 seconds
cursor = conn.cursor()
try:
cursor.execute("INSERT INTO employees (name, position) VALUES (?, ?)", ('Sam Smith', 'Data Analyst'))
finally:
cursor.close()
conn.close()
期待される出力:
出力はありませんが、タイムアウトによって一時的なロックを乗り越える猶予が得られます。
ヒント: Beekeeper Studio では、以前「database is locked」エラーで失敗したクエリを再実行して、タイムアウトやリトライで問題が解決したかを確認できます。コードを編集せずに変更を手早くテストできる方法です。
解決策 4: 長時間実行されるトランザクションを避ける
トランザクションを短く保ち、データベースがロックされる時間を最小限に抑えましょう。これにより、「database is locked」エラーが発生する可能性が低くなります。
例:
BEGIN TRANSACTION;
INSERT INTO employees (name, position) VALUES ('Alice Johnson', 'HR Manager');
COMMIT;
期待される出力:
出力はありませんが、トランザクションが素早く完了し、ロック時間が短縮されます。
まとめ
「SQLite database is locked」エラーは、通常、同時実行の問題や、データベース接続・トランザクションの管理ミスが原因で発生します。トランザクションを効率的に管理する、接続を適切に使用する、適切なタイムアウトを設定する、長時間実行されるトランザクションを避けるといった上記のベストプラクティスに従えば、このエラーを防ぐことができます。これらの方法により、SQLite データベースの操作を堅牢かつ効率的に行えます。
実際に試してみましょう
Beekeeper Studio では、どんな .db ファイルでも開いてテーブルを確認し、クエリを実行して、変更が正しく反映されているかを確かめられます。オープンソースで、20 種類以上のデータベースに接続でき、Windows、macOS、Linux で快適に動作します。
Beekeeper Studioは無料のオープンソースのデータベースGUIです
これまで使った中で最高のSQLクエリ&エディタツールです。データベースの管理に必要なものがすべて揃っています。 - ⭐⭐⭐⭐⭐ Mit
Beekeeper Studioは高速で直感的、そして使いやすいツールです。多数のデータベースに対応し、Windows、Mac、Linuxで快適に動作します。
Beekeeper Studio 利用者の声
「Beekeeper Studio で以前の SQL ワークフローを完全に置き換えました。高速で直感的、データベース作業がまた楽しくなりました。」
「多くのデータベース GUI を試してきましたが、Beekeeper は機能とシンプルさのバランスが完璧です。とにかくちゃんと動きます。」