You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SQLAlchemy读写分离下commit后访问实例报已删除错误

问题根源

你的问题是两个机制共同作用导致的:

  1. SQLAlchemy默认在commit()后会过期所有实例(expire_on_commit=True),当你访问实例属性(比如User.userId)时,会自动触发SELECT查询重新从数据库加载数据。
  2. 你的RoutingSession把所有SELECT都路由到读实例,但读写分离架构下主从同步存在延迟,刚提交到写实例的数据还没同步到读实例,导致查询不到数据,抛出实例不存在的错误。

方案1:关闭commit后的实例过期(简单直接)

创建Session时添加expire_on_commit=False配置,让commit后实例的属性保留在内存中,访问时不再触发数据库查询:

Session = sessionmaker(
    class_=RoutingSession, 
    autocommit=False, 
    autoflush=True,
    expire_on_commit=False  # 新增该配置
)
db_session = scoped_session(Session)
  • 优点:代码改动极小,适合提交后短时间内需要访问实例属性的场景。
  • 缺点:实例不会自动感知数据库中后续的变更,如果其他操作修改了这条记录,内存中的实例数据会和数据库不一致。

方案2:修改路由逻辑,让实例刷新查询走写实例(更严谨)

如果需要保留expire_on_commit=True的默认行为(保证数据一致性),可以修改RoutingSession的get_bind方法,识别SQLAlchemy内部用于刷新实例的主键查询,强制这类查询路由到写实例:

from sqlalchemy.sql import Select

class RoutingSession(Session):     
    def get_bind(self, mapper=None, clause=None):  
        # 优先处理实例刷新的主键查询:这类查询是commit后加载实例用的,必须走写库
        if clause is not None and isinstance(clause, Select) and mapper is not None:
            primary_key_cols = set(mapper.primary_key)
            query_cols = set(clause.columns)
            # 判断查询是否仅包含主键列,且条件为主键等值匹配(SQLAlchemy刷新实例的特征)
            if primary_key_cols.issuperset(query_cols):
                where_clause = clause.whereclause
                if (hasattr(where_clause, 'left') 
                    and where_clause.left in primary_key_cols
                    and hasattr(where_clause, 'right') 
                    and not hasattr(where_clause.right, 'name')):
                    return engines["write"]
        
        # 原有路由逻辑
        if isinstance(clause, (Select)):
            return engines["read"]
        else:
            return engines["write"]
  • 原理:SQLAlchemy刷新过期实例时,会执行一条仅查询主键、条件为当前实例主键值的SELECT语句,我们通过识别这类查询的特征,强制让它走写实例,确保能读到刚提交的数据。

额外建议

如果业务允许,可以调整MySQL主从同步策略(比如半同步复制)来降低延迟,但代码层面的修复是更直接的解决方案。

内容的提问来源于stack exchange,提问作者Rajendra Khabiya

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 13:07:35