我正在调试一段Python代码中出现的奇怪现象:
def insert_book(name):
with engine.connect() as connection:
insert_statement = sqlalchemy.text(
"""
INSERT INTO books (title_id)
SELECT
title_id
FROM titles
WHERE name = :name;
"""
).bindparams(name=name)
result = connection.execute(insert_statement)
return result.lastrowid
我正在使用的 MySQL 数据库表的结构如下:
CREATE TABLE `titles` (
`title_id` int NOT NULL AUTO_INCREMENT,
`name` varchar(36),
PRIMARY KEY (`title_id`),
UNIQUE KEY `name` (`name`)
);
CREATE TABLE `books` (
`book_id` int NOT NULL AUTO_INCREMENT,
`title_id` int DEFAULT NULL,
PRIMARY KEY (`book_id`),
KEY `client_id` (`title_id`),
CONSTRAINT `titles_fk` FOREIGN KEY (`title_id`) REFERENCES `titles` (`title_id`)
);
两个表都已插入几行。
当我在 Flask 应用程序中运行 Python 代码(使用从
name
表获取的 titles
)并将 SQLAlchemy 指向我的 MySQL 数据库时,会发生两件事:
result.lastrowid
包含一个新的自动递增 int 值。当我重复此操作时,返回的 int 值会正确递增,但不会创建任何行。
我的问题是:为什么会发生这种情况以及如何解决它?
以下是主要使用的包:
请: 请不要指向其他公认更好的 SQLAlchemy API。我想了解为什么这段特定的代码行为不当。谢谢你。
更新:我检查了 MySQL 云实例的日志,发现了与插入失败相对应的错误:
中止连接...到数据库:'...'用户:'...'主机:'...'(读取通信数据包时出错)。”
with engine.connect() as conn:
conn.exec_driver_sql("INSERT INTO my_table …")
print("Context manager exited.")
将自动回滚更改,因为未调用
conn.commit()
。在 SQLAlchemy 教程中,这被称为“随心所欲地提交”工作方式。
相比之下,
with engine.begin() as conn:
conn.exec_driver_sql("INSERT INTO my_table …")
print("Context manager exited.")
当上下文管理器退出时将自动提交更改(除非发生错误)。这称为“开始一次”风格。