• sqlalchemy expire_all 方法详解,强制刷新会话缓存


    在 SQLAlchemy 中,expire_all() 方法是 Session 类的一个重要方法,用于使会话(Session)中所有当前加载的对象过期。这意味着下次访问任何已加载对象的属性时,SQLAlchemy 将从数据库中重新加载这些对象的最新状态。这是一个强制刷新加载对象状态的方法,确保您获取的是数据库中的最新数据。

    功能

    当您调用 session.expire_all() 时,会发生以下事情:

    1. 标记所有对象为过期:在该会话中加载的所有对象都被标记为“过期”。这意味着它们的当前状态将被丢弃,而不是从会话的缓存中提取。

    2. 延迟加载:在下次访问这些对象的任何属性时,SQLAlchemy 会自动从数据库中重新加载它们的最新状态。这是一个延迟操作,只有在实际访问属性时才会触发。

    3. 不影响未修改的对象:即使对象自加载后未被修改,它们的状态也会被清除并在下次访问时重新加载。

    使用场景

    您可能会在以下情况下使用 expire_all():

    1. 保证数据一致性:在长时间运行的会话中,为了确保获取到数据库中的最新数据,可以使用 expire_all() 方法。

    2. 避免脏读:在有可能发生并发修改的场景中,使用 expire_all() 可以防止读取到过时的数据。

    3. 手动刷新状态:在某些复杂的交互逻辑中,您可能需要手动刷新对象状态,以确保应用逻辑的正确性。

    示例

    from sqlalchemy.orm import sessionmaker
    from my_model import MyModel  # 假设您有一个模型类 MyModel
    from sqlalchemy import create_engine
    
    # 创建会话
    engine = create_engine("sqlite:///mydatabase.db")
    Session = sessionmaker(bind=engine)
    session = Session()
    
    # 查询并使用对象
    my_object = session.query(MyModel).first()
    print(my_object.some_attribute)
    
    # 确保从数据库重新加载对象
    session.expire_all()
    
    # 当再次访问属性时,将从数据库重新加载它的最新状态
    print(my_object.some_attribute)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    SQLAlchemy 2.0 代码展示

    print("=====================================会话缓存==================================================")
    
    # 第一次查询,并加载用户的所有关联部门项
    sql1 = select(models.VadminUser).where(models.VadminUser.id == 1).options(joinedload(models.VadminUser.depts))
    queryset1 = await self.db.scalars(sql1)
    user1 = queryset1.unique().first()
    print(f"用户编号:{user1.id} 用户姓名:{user1.name} 关联部门 {[i.name for i in user1.depts]}")
    
    # 第二次即使没有加载用户关联的部门,同样可以访问,因为这里会默认从会话缓存中获取
    sql2 = select(models.VadminUser).where(models.VadminUser.id == 1)
    queryset2 = await self.db.scalars(sql2)
    user2 = queryset2.first()
    print(f"用户编号:{user2.id} 用户姓名:{user2.name} 关联部门 {[i.name for i in user2.depts]}")
    
    # 使当前会话(Session)中所有已加载的对象过期,确保您获取的是数据库中的最新数据。
    self.db.expire_all()
    
    print("===================查询出来,即使没有通过.访问属性,同样会产生缓存=====================")
    
    # 第一次查询,并加载用户的所有关联部门项,但是不访问用户的属性
    sql3 = select(models.VadminUser).where(models.VadminUser.id == 1).options(joinedload(models.VadminUser.depts))
    queryset3 = await self.db.scalars(sql3)
    user3 = queryset3.unique().first()
    print(f"没有访问属性,也会产生缓存")
    
    # 第二次即使没有加载用户关联的部门,同样可以访问,因为这里会默认从会话缓存中获取
    sql4 = select(models.VadminUser).where(models.VadminUser.id == 1)
    queryset4 = await self.db.scalars(sql4)
    user4 = queryset4.first()
    print(f"用户编号:{user4.id} 用户姓名:{user4.name} 关联部门 {[i.name for i in user4.depts]}")
    
    # 使当前会话(Session)中所有已加载的对象过期,确保您获取的是数据库中的最新数据。
    self.db.expire_all()
    
    print("=====================================数据列表会话缓存==================================================")
    
    # 第一次查询出所有用户,并加载用户的所有关联部门项
    sql5 = select(models.VadminUser).options(joinedload(models.VadminUser.depts))
    queryset5 = await self.db.scalars(sql5)
    datas5 = queryset5.unique().all()
    for data in datas5:
        print(f"用户编号:{data.id} 用户姓名:{data.name} 关联部门 {[i.name for i in data.depts]}")
    
    # 第二次即使没有加载用户关联的部门,同样可以访问,因为这里会默认从会话缓存中获取
    sql6 = select(models.VadminUser)
    queryset6 = await self.db.scalars(sql6)
    datas6 = queryset6.unique().all()
    for data in datas6:
        print(f"用户编号:{data.id} 用户姓名:{data.name} 关联部门 {[i.name for i in data.depts]}")
    
    # 使当前会话(Session)中所有已加载的对象过期,确保您获取的是数据库中的最新数据。
    self.db.expire_all()
    
    print("===================expire 单个对象过期=====================")
    
    # 第一次查询,并加载用户的所有关联部门项
    sql7 = select(models.VadminUser).where(models.VadminUser.id == 1).options(joinedload(models.VadminUser.depts))
    queryset7 = await self.db.scalars(sql7)
    user7 = queryset7.unique().first()
    print(f"用户编号:{user7.id} 用户姓名:{user7.name} 关联部门 {[i.name for i in user7.depts]}")
    
    # 使当前会话(Session)中的 user7 对象过期,再次访问就会重新查询数据库数据
    self.db.expire(user7)
    
    # 第二次查询会发现会话中没有该对象的缓存,会重新在数据库中查询
    sql8 = select(models.VadminUser).where(models.VadminUser.id == 1)
    queryset8 = await self.db.scalars(sql8)
    user8 = queryset8.first()
    try:
        print(f"用户编号:{user8.id} 用户姓名:{user8.name} 关联部门 {[i.name for i in user8.depts]}")
    except StatementError:
        print("访问部门报错了!!!!!")
    
    # 使当前会话(Session)中所有已加载的对象过期,确保您获取的是数据库中的最新数据。
    self.db.expire_all()
    
    print("=========expire 单个对象过期后,重新访问之前对象的属性也会重新查询数据库,但是不会重新加载关系===========")
    
    # 第一次查询,并加载用户的所有关联部门项
    sql9 = select(models.VadminUser).where(models.VadminUser.id == 1).options(joinedload(models.VadminUser.depts))
    queryset9 = await self.db.scalars(sql9)
    user9 = queryset9.unique().first()
    print(f"用户编号:{user9.id} 用户姓名:{user9.name} 关联部门 {[i.name for i in user9.depts]}")
    
    # 使当前会话(Session)中的 user9 对象过期,再次访问就会重新查询数据库数据
    self.db.expire(user9)
    
    # 第二次查询会发现会话中没有该对象的缓存,会重新在数据库中查询,但是不会重新加载关系
    try:
        print(f"用户编号:{user9.id} 用户姓名:{user9.name} 关联部门 {[i.name for i in user9.depts]}")
    except StatementError:
        print("访问部门报错了!!!!!")
    
    print("=====================================结束==================================================")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94

    在这个示例中,使用 expire_all() 后,当再次访问 my_object.some_attribute 时,SQLAlchemy 将从数据库中重新加载 MyModel 对象的最新状态。

  • 相关阅读:
    学习Oracle数据库的新建表的基本操作(二)
    【网络安全】SSL Pinning及其绕过
    js数据结构(队列Queue)
    Docker从初学到进阶二(使用Docker命令,自定义镜像,部署微服务集群,配置自己的镜像仓库)
    Opengl绘制三角形
    pandas数据分析 - 分组聚合、分组转换、分组筛选
    PyTorch常用参数初始化方法详解
    【Java SE】继承
    【ES6闯关】Promise堪比原生的自定义封装then、catch、resolve、reject...
    三个线程循环打印ABC
  • 原文地址:https://blog.csdn.net/k_genius/article/details/135490378