テクノロジー · 実用ガイド
Python の SQLite バックアップが停止?コミット前に両接続を確認
コピー元の未確定更新、使用中のコピー先、別接続のロックを切り分けます。トランザクションのフラグだけでは対処を決められません。

Python の SQLite バックアップは、よくあるロック例外を出さずに再試行を続けることがあります。commit() の追加で直る例もありますが、補助関数が決定すべきでない業務更新まで確定させるおそれがあります。まずコピー元、コピー先、未完了の処理を特定します。
12 個の小規模な対照試験で、止まったコピー、コピー先の即時拒否、成功する読み取りトランザクションを区別しました。in_transaction=True は調査の手掛かりであり、コミットの指示でも、すべてのバックアップを拒否する根拠でもありません。
1. 状態を変更する前に両接続の役割を記録する
Python と sqlite3.sqlite_version、実際の呼び出し、両データベースのパス、各接続の autocommit、isolation_level、in_transaction を記録します。最後の SQL とトランザクションの責任者も特定します。コピー先には一意な名前の独立した候補ファイルを使い、稼働中のコピー元や保持すべき旧バックアップを指定しないでください。
最初の進捗コールバックより前の失敗か、繰り返し呼ばれた後の停滞かを確認します。状態、残りページ数、総ページ数は組で記録します。SQLite はバックアップ中のコピー先接続の使用を制限しているため、その接続でクエリを実行しません。busy 状態なら残りがゼロでも完了の証明にはなりません。
2. 真偽値をそのまま診断にしない
Linux 上の CPython 3.12.14 と SQLite 3.53.1 では、コピー元の未コミット INSERT が状態 5、SQLITE_BUSY を繰り返しました。診断用コールバックで 3 回後に停止しました。試験の責任者が意図してコミットすると同じコピー元から成功しました。別接続の排他ロックも状態 5 となり、数値だけでは責任者を特定できませんでした。
autocommit=False では、空の遅延トランザクションとテーブルを読んだコピー元の両方が、in_transaction=True のまま成功しました。同モードの新しいコピー先も、読み取り前は成功しました。しかし SELECT 後の再バックアップは、進捗を呼ばずに「destination database is in use」で失敗しました。未確定更新のあるコピー先も拒否されました。フラグより役割と実際の処理が重要です。
3. どのデータを含めるかを決める
コピー元の未確定更新を含めるなら、アプリケーションのトランザクション責任者が意図した処理単位を終えてから再試行します。症状を消すためだけに汎用補助関数からコミットしません。Python の仕様では autocommit=True への変更は保留中のトランザクションをコミットするため、既存接続の属性変更は実データの判断です。
ファイル型データベースなら、専用の読み取り専用接続で、書き手をコミットせず確定済みデータをコピーできます。対照試験では書き手に未確定の行 2 が見える間、別の読み手のバックアップには行 1 だけが入りました。行 2 を除外した成功です。単純な :memory: への別接続は別のデータベースなので、この方法をそのまま転用できません。
4. バックアップのコールバックで再試行を制限する
試験した CPython 実装は SQLITE_OK、SQLITE_BUSY、SQLITE_LOCKED でループします。進捗コールバックは各ステップ後に実行され、そこから例外を出すと処理を終了して中止します。接続のロック待ち timeout はバックアップ全体の期限ではありません。SQL 実行用の進捗ハンドラーと混同せず、backup(progress=...) を使います。
総経過時間を制限するなら、開始前に time.monotonic() で期限を決めます。コールバックで 3 引数を記録し、期限超過かつ状態が SQLITE_DONE 以外なら TimeoutError を出します。進行しながら再開する処理も制限するには期限を固定します。接続 timeout をゼロ、期限を 0.03 秒にしたロック対照では約 0.03 秒で例外になりました。ステップ間の協調的検査であり、停止したシステム呼び出しへの厳密な時間保証ではありません。
5. 中止とバックアップの受け入れを分ける
拒否やコールバック例外の後は専用接続を閉じ、候補を利用可能なバックアップに含めません。ファイルの存在、コールバックの実行、例外の捕捉だけで昇格させないでください。成功時はコピー先を閉じ、その候補を開き直して整合性と必要な業務データを確認します。関連ガイドがこの後段を扱います。
試験は小さなローカルおよびメモリ内データベースとロールバックジャーナルに限定しました。WAL への継続書き込み、ネットワークファイルシステム、ORM、全 Python 版は未検証です。独立した Hermes の報告は、連続 busy 再試行を制限する 2026 年 8 月 16 日の修正マージにつながりました。そのアプリ固有の方針は共通の総期限ではありません。コピー元を保持し、完了方針を明確にしてから次を試します。
