如何让SQLAlchemy的on_conflict_do_update.returning返回更新后的值?
解决Upsert返回旧数据及事务回滚问题
1. 让Upsert直接返回更新后的数据
问题根源在于你的on_conflict_do_update中使用set_=data,未引用插入操作的新值对象(excluded),导致RETURNING返回更新前的旧数据,同时SQLAlchemy的会话缓存也可能干扰结果。
修改Upsert函数
首先导入PostgreSQL专属的excluded对象(其他数据库如MySQL有类似逻辑但语法不同):
from sqlalchemy.dialects.postgresql import excluded
然后调整upsert函数的set_参数,用excluded引用插入的新值:
def upsert(model, data, constraints): insert_stmt = insert(model).values(data) do_update_stmt = insert_stmt.on_conflict_do_update( index_elements=constraints, # 通过excluded引用插入的新值,确保RETURNING返回更新后的数据 set_={col: excluded[col] for col in data.keys()} ) return do_update_stmt
确保会话获取最新数据
如果修改后仍拿到旧对象,需要主动刷新会话中的对象:
upsert_response = db.session.execute(upsert_query.returning(model)) updated_model = upsert_response.fetchone()[0] # 刷新对象,强制从数据库读取最新状态 db.session.refresh(updated_model)
这样就能在事务未提交的情况下拿到更新后的数据,后续业务逻辑失败时执行db.session.rollback()即可回滚所有操作。
2. 关于提交后回滚的问题
一旦执行db.session.commit(),事务就会持久化到数据库,无法再回滚。你的业务场景必须遵循以下流程:
- 所有依赖更新后数据的业务逻辑都放在
commit()之前执行 - 仅当所有业务逻辑执行成功后,才调用
db.session.commit() - 任何步骤失败,立即执行
db.session.rollback()撤销所有未提交的操作
内容的提问来源于stack exchange,提问作者user10616138
相关产品推荐
相关产品推荐

