两次运行SQLAlchemy建表代码为何输出存在差异?
为什么两次运行SQLAlchemy的
metadata.create_all(engine)输出内容不同? 这其实是SQLAlchemy设计上的贴心特性——create_all()方法是幂等的,它只会在必要的时候执行建表操作,具体差异原因可以拆成两次运行的行为来看:
第一次运行:全新建表
当你第一次运行这段代码时,college.db这个SQLite数据库里还没有users和addresses这两张表。此时metadata.create_all(engine)会:
- 根据你定义的
Table对象生成对应的CREATE TABLESQL语句 - 执行这些语句在数据库中创建表
- 因为你给
create_engine()传了echo=True参数(这个参数会打印所有SQLAlchemy执行的SQL语句),所以会直接输出建表的SQL代码,也就是你看到的:
CREATE TABLE addresses ( id INTEGER NOT NULL, user_id INTEGER, email_address VARCHAR NOT NULL, PRIMARY KEY (id), FOREIGN KEY(user_id) REFERENCES users (id) -- 注:实际还会包含users表的CREATE TABLE语句,你可能没贴全
第二次及后续运行:仅检查表存在性
当数据库里已经存在这两张表之后,create_all()就不会再执行建表操作了。它会先做表存在性校验:
- 对于SQLite数据库,SQLAlchemy会通过
PRAGMA table_info("table_name")这个语句来查询每张表的元数据,确认表是否已经存在 - 同时,它还会执行一些基础的SQL兼容性测试(就是那些
SELECT CAST('test plain returns'...)的语句),确保数据库连接正常且符合预期 - 因为没有建表操作要执行,所以输出的都是这些检查用的SQL语句和执行日志,也就是你看到的那些时间戳开头的INFO日志:
2019-04-18 21:06:57,881 INFO sqlalchemy.engine.base.Engine SELECT CAST('test plain returns' AS VARCHAR(60)) AS anon_1 2019-04-18 21:06:57,886 INFO sqlalchemy.engine.base.Engine () 2019-04-18 21:06:57,892 INFO sqlalchemy.engine.base.Engine SELECT CAST('test unicode returns' AS VARCHAR(60)) AS anon_1 2019-04-18 21:06:57,899 INFO sqlalchemy.engine.base.Engine () 2019-04-18 21:06:57,904 INFO sqlalchemy.engine.base.Engine PRAGMA table_info("users") 2019-04-18 21:06:57,909 INFO sqlalchemy.engine.base.Engine () 2019-04-18 21:06:57,923 INFO sqlalchemy.engine.base.Engine PRAGMA table_info("addresses") 2019-04-18 21:06:57,928 INFO sqlalchemy.engine.base.Engine () 2019-04-18 21:07:17,156 INFO sqlalchemy.engine.base.Engine PRAGMA table_info("users") 2019-04-18 21:07:17,157 INFO sqlalchemy.engine.base.Engine ()
简单总结:create_all()的核心逻辑是「只创建不存在的表」,所以第一次运行输出建表SQL,后续运行只输出检查表的日志,这是完全正常的设计,目的是让你可以安全地重复运行这段代码,不用担心重复建表导致的错误。
内容的提问来源于stack exchange,提问作者Việt Anh
相关产品推荐
相关产品推荐

