6

MySQL データベースがハングする非常に単純なコードがあります。

import sqlalchemy as sa
from sqlalchemy import orm

# creating the engine, the base, etc
import utils
import config

utils.base_init(config)
Base = config.Base

class Parent(Base):
    __tablename__ = 'Parents'
    id = sa.Column(sa.Integer, primary_key=True)
    children = orm.relationship('Child', backref='parent')

class Child(Base):
    id = sa.Column(sa.Integer, primary_key=True)
    parent_id = sa.Column(sa.Integer)

    __tablename__ = 'Children'

    __table_args__ = (sa.ForeignKeyConstraint(
        ['parent_id'],
        ['Parents.id'],
        onupdate='CASCADE', ondelete='CASCADE'),{})

Base.metadata.create_all()

session = orm.sessionmaker(bind=config.Base.metadata.bind)()
p = Parent(id=1)
c1 = Child(id=1)
c2 = Child(id=2)
session.add(p)
session.add(c1)
session.add(c2)
session.commit()

# Works
# Base.metadata.drop_all()

c1.parent
# 2012-08-17 20:16:21,459 INFO sqlalchemy.engine.base.Engine BEGIN (implicit)
# 2012-08-17 20:16:21,460 INFO sqlalchemy.engine.base.Engine SELECT `Children`.id AS `Children_id`, `Children`.parent_id AS `Children_parent_id` 
# FROM `Children` 
# WHERE `Children`.id = %s
# 2012-08-17 20:16:21,460 INFO sqlalchemy.engine.base.Engine (1,)



Base.metadata.drop_all()
# hangs until i kill the connection above.
# server status: 'Waiting for table metadata lock'

リレーションシップ属性をロードするために必要な選択クエリを発行した後、SQL Alchemy がメタデータ ロックを解放していないように見えますか? どうすれば解放してもらえるでしょうか?そもそも、select ステートメントでテーブルをロックする必要がある理由がわかりません。

もちろん、セッションを閉じることでこの特定のコードを動作させることはできますが、それは私の実際のプログラムでは実用的ではありません。

4

1 に答える 1

2

.drop_all()呼び出しの前に新しいトランザクションを開始する必要があります。MySQLは、このトランザクションでテーブルからの読み取りを確認し、テーブルが削除されないようにロックします。

session.commit()
Base.metadata.drop_all()

トランザクションをコミットすると、暗黙的に新しいトランザクションが開始されます。

MySQLはトランザクション分離について保証します。トランザクションは一貫性のあるデータを読み取り、新しいトランザクションを開始するまで他のトランザクションによってコミットされた変更を確認しません。ただし、ステートメントを使用するDROP TABLEと、MySQLがこれらの保証を維持できなくなるため、テーブルがロックされます。

または、トランザクション分離レベルを変更して、分離保証を気にしないようにMySQLに指示することもできます。セッション接続はプールされるため、これはすべての接続に対してのみ実行できるか、まったく実行できません。isolation_level引数を使用してcreate_engine()

engine = create_engine(
    'mysql://username:passwd@localhost/databasename',
    isolation_level='READ UNCOMMITTED')

各分離レベルの詳細については、SET TRANSACTIONドキュメントを参照してください。

于 2012-08-18T15:06:42.997 に答える