说明
创建 session 工厂对象时,代码如下:
async_session = async_sessionmaker(
async_engine, # 绑定数据库引擎
class_=AsyncSession, # 指定会话类,调用 async_session() 返回的类型
expire_on_commit=False
)
expire_on_commit 的默认值是 True,需要将 expire_on_commit 设置为 False
作用:执行 commit 后,会话中的 表模型对象 不过期,再次访问对象中的属性(即:表中的字段),不需要重新查询数据库
expire_on_commit 设置为 True
代码修改为:
async_session = async_sessionmaker(
async_engine, # 绑定数据库引擎
class_=AsyncSession, # 指定会话类,调用 async_session() 返回的类型
expire_on_commit=True
)
或者去掉 expire_on_commit 参数
测试
修改 main.py 文件,内容如下:
@app.post('/user')
async def save_user(username:str,password:str, db = Depends(get_db)):
user = User(username = username,password = password)
await save(db,user)
# 关键:在 save()中已经执行 commit() 了,之后再访问对象属性会报错
return {
"code":200,
"msg":f"添加成功!用户id:{user.id}"
}
关键:在 save() 中已经执行 commit() 了,之后再访问对象属性会报错,如:user.id
执行测试
报错
原因
await save(db, user)内部执行await db.commit()- 默认
expire_on_commit=True,执行commit()后,user对象标记为expired过期 return里读取user.id,对象过期,SQLAlchemy 尝试自动SELECT刷新对象AsyncSession不能同步执行数据库 IO,直接抛MissingGreenlet错误
解决
解决方法有若干种,这里用:增加 await db.refresh(user)
代码
@app.post('/user')
async def save_user(username:str,password:str, db = Depends(get_db)):
user = User(username = username,password = password)
await save(db,user)
# commit后再刷新模型对象,会自动查询
await db.refresh(user)
return {
"code":200,
"msg":f"添加成功!用户id:{user.id}"
}
执行测试
程序能够正确执行,但看控制台,发现 commit() 后,又再次执行查询了:
结论
如果将 expire_on_commit 设置为 True ,commit 后模型对象已经过期,不能再用。
再次访问对象属性(即:表中的字段值),为了避免报错,需要加额外代码,导致再次查询数据
所以:expire_on_commit 设置为 False


