SQLAlchemy执行DROP TABLE后,已删除表仍存在于MetaData中的原因
问题:执行DROP表后,MetaData中仍存在该表的原因
我正在进行基础SQLAlchemy练习,尝试先创建表再删除它,最后通过print语句列出操作后的表。但执行DROP语句后,'test deck'表仍出现在MetaData中,代码及输出如下:
代码
from sqlalchemy import MetaData, Table, Column, String, Boolean from sqlalchemy import create_engine engine = create_engine('sqlite://', echo = True) metadata_obj = MetaData() with engine.connect() as conn: table_obj = Table('test deck', metadata_obj, Column('Name', String, primary_key = True)) metadata_obj.create_all(conn) metadata_obj.tables['test deck'].drop(conn) metadata_obj.reflect(engine) print(metadata_obj.tables.keys())
输出
2023-09-17 14:22:28,844 INFO sqlalchemy.engine.Engine BEGIN (implicit) 2023-09-17 14:22:28,844 INFO sqlalchemy.engine.Engine PRAGMA main.table_info("test deck") 2023-09-17 14:22:28,844 INFO sqlalchemy.engine.Engine [raw sql] () 2023-09-17 14:22:28,844 INFO sqlalchemy.engine.Engine PRAGMA temp.table_info("test deck") 2023-09-17 14:22:28,844 INFO sqlalchemy.engine.Engine [raw sql] () 2023-09-17 14:22:28,845 INFO sqlalchemy.engine.Engine CREATE TABLE "test deck" ( "Name" VARCHAR NOT NULL, PRIMARY KEY ("Name") ) 2023-09-17 14:22:28,845 INFO sqlalchemy.engine.Engine [no key 0.00006s] () 2023-09-17 14:22:28,845 INFO sqlalchemy.engine.Engine DROP TABLE "test deck" 2023-09-17 14:22:28,845 INFO sqlalchemy.engine.Engine [no key 0.00006s] () 2023-09-17 14:22:28,845 INFO sqlalchemy.engine.Engine ROLLBACK 2023-09-17 14:22:28,845 INFO sqlalchemy.engine.Engine BEGIN (implicit) 2023-09-17 14:22:28,845 INFO sqlalchemy.engine.Engine SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite~_%' ESCAPE '~' ORDER BY name 2023-09-17 14:22:28,845 INFO sqlalchemy.engine.Engine [raw sql] () 2023-09-17 14:22:28,846 INFO sqlalchemy.engine.Engine SELECT name FROM sqlite_temp_master WHERE type='table' AND name NOT LIKE 'sqlite~_%' ESCAPE '~' ORDER BY name 2023-09-17 14:22:28,846 INFO sqlalchemy.engine.Engine [raw sql] () 2023-09-17 14:22:28,846 INFO sqlalchemy.engine.Engine ROLLBACK dict_keys(['test deck'])
原因分析
MetaData内存状态与数据库操作不同步
你通过Table('test deck', metadata_obj, ...)创建表对象时,已将该表的定义添加到metadata_obj的内存字典中。SQLAlchemy的MetaData不会自动根据数据库的变化(如DROP表)移除自身内存中的表对象,除非手动清理或使用新的MetaData实例。事务未提交导致操作被回滚
从输出日志的ROLLBACK可知,with engine.connect()上下文内的所有操作都被回滚了:
engine.connect()开启的连接默认处于事务模式,若未手动调用conn.commit(),上下文结束时会自动回滚所有操作。- 这意味着数据库实际上既没有创建表,也没有执行DROP操作,但
metadata_obj内存中仍保留着最初定义的表对象。
- reflect方法的默认行为
metadata_obj.reflect(engine)默认仅将数据库中存在的表添加到MetaData中,不会移除MetaData中已存在但数据库里没有的表对象。因此即使数据库中无对应表,metadata_obj.tables仍保留初始定义的'test deck'表。
解决办法
- 提交事务确保操作生效:在
with块内添加conn.commit(),让create和drop操作真正作用于数据库:
with engine.connect() as conn: table_obj = Table('test deck', metadata_obj, Column('Name', String, primary_key = True)) metadata_obj.create_all(conn) metadata_obj.tables['test deck'].drop(conn) conn.commit() # 提交事务
- 手动清理MetaData中的表对象:若需移除内存中的表定义,可手动删除:
del metadata_obj.tables['test deck']
- 使用新MetaData实例反射:若只想获取数据库中实际存在的表,创建新的
MetaData实例进行反射:
new_metadata = MetaData() new_metadata.reflect(engine) print(new_metadata.tables.keys())
内容的提问来源于stack exchange,提问作者placebo_me_please
相关产品推荐
相关产品推荐

