15

最新の sqlalchemy を使用する python スクリプトがあります。sqlite を使用すると、sqlite のみ、他のデータベースは正常に動作しますが、次のエラーが発生します。

sqlalchemy.exc.OperationalError: (OperationalError) database is locked u'SELECT blabla....

ヒントはありますか?

私のコードの例(簡略化)、私は物事を選択、更新、削除するために、このようないくつかの方法を持っています:

class MyDb(object):
    def __init__(self):
        engine = create_engine("sqlite:///file", poolclass=NullPool, pool_threadlocal=True)
        engine.pool_size=1
        engine.pool_timeout = 60
        self.sess = sessionmaker(bind=engine)

    def del_stuff(self):
        sess = self.sess()
        sess.query(Stuff).delete()
        try:
            sess.commit()
        except:
            sess.rollback()

    def set_stuff(self, id, bar):
        sess = self.sess()
        sess.query(Foo).get(id).bar = bar
        try:
            sess.commit()
        except:
            sess.rollback()
4

12 に答える 12

27

SQLite は、UPDATE、INSERT、または DELETE が送信されたときなど、データベースへの書き込みが行われると、データベースをロックします。ORM を使用する場合、これらはフラッシュで送信されます。データベースは、COMMIT または ROLLBACK が発生するまでロックされたままになります。

マルチスレッドの状況では、「データベースがロックされています」というエラーがほとんど見られます。1 つのスレッドがデータベースをロックし、別のスレッドが独自の書き込みを試みます。最初のスレッドがタイムアウト時間内にロックを解放しない場合 (デフォルトでは 4 ~ 5 秒、思い出せば 4 秒)、2 番目のスレッドで OperationalError が発生します。

いつフラッシュが発生するかを知るのは難しい場合があります。そのため、クエリがフラッシュを引き起こすため、セッションが (デフォルト設定) になったときにデータベースへの書き込みが行わますautoflush=True。SQL ロギングをオンにすると、状況がいつ発生したかを明確にするのに役立つ場合があります。

logging.getLogger('sqlalchemy.engine').setLevel(logging.INFO)

関連するドキュメントがいくつかあります: http://docs.sqlalchemy.org/en/rel_0_9/dialects/sqlite.html#database-locking-behavior-concurrency

于 2015-02-26T16:36:28.630 に答える
5

sqlite データベースでは、一度に 1 つのプロセスしかアクセスできません。おそらく、データベースを使用する別のプロセスがありますか?

于 2012-12-15T19:07:44.627 に答える
5

開発者ツールを使用して、データベースで保留中のコミットを確認します。

上で誰もが言ったように、sqlite データベースでは、一度に 1 つのプロセスしかアクセスできません。私の場合、sqliteに DB ブラウザーを使用していますが、同じようにクエリをコミットしませんでした。これもDBをロックし、アプリケーションがデータベースに書き込むことを許可しません。

于 2019-04-04T02:44:40.903 に答える
4

スレッド内のすべてのオブジェクトで単一のセッションを使用する必要があります。sqlite は実際には複数の接続が好きではなく、sqlalchemy は実質的にセッションごとの接続です (クラスごとにセッションがあるように見えますが、これは単一のスレッドに複数のセッションがあることを意味します)。

于 2013-02-05T22:39:15.837 に答える
4
于 2019-07-24T22:15:05.993 に答える
2

次の点についてコードを確認してください。

  1. MyDb のインスタンスは、すべてのアプリケーションの有効期間に対して 1 つである必要があります。MyDb はシングルトンでなければなりません。
  2. エンジンに「プレーン」戦略を使用してみてください。pool_threadlocal=True
  3. 各論理リクエストでセッションを閉じます。

例えば:

def set_stuff(self, id, bar):
    sess = self.sess()
    sess.query(Foo).get(id).bar = bar
    try:
        sess.commit()
    except:
        sess.rollback()
    finally:
        sess.close()
于 2012-12-18T10:17:18.137 に答える
0

将来の参加者のために、私の場合、to_sqlCIFS共有マウント上のsqliteファイルに書き込むpandas関数(sqlalchemy接続文字列を使用)が失敗していました。ext4 ディスクでも同じ機能が動作します。修正はnobrl、 のオプションに追加し/etc/fstab、ディスクをアンマウントしてから再マウントすることでした。その後、to_sqlコマンドは機能しました。

于 2021-11-19T14:40:44.257 に答える
-1

私の答えは、flask データベースを試していて、データベース ロックを解除するためにデータベースを削除する準備ができている人だけです。実験している場合は、Python スクリプトを実行することで、テーブルにデータを再度追加できます。

どうぞ....

  1. フラスコ プロジェクトにある data.sqlite ファイルを削除します。

  2. フラスコ プロジェクトにある migrations フォルダーを削除します。

  3. 次のコマンドを実行して、新しいデータベースを作成します。

    • フラスコデータベースの初期化
    • フラスコ db 移行 -m "テーブル"
    • フラスコデータベースのアップグレード
  4. これで、Python スクリプトを実行してデータベースにデータを追加したり、Python Promt/Flask シェルを使用して手動でテーブルにデータを追加したりできます。

于 2019-11-22T11:07:55.837 に答える
-3

これは、テーブルに重複するレコードがある場合に発生する可能性があります

于 2020-11-26T09:44:45.070 に答える