SQLAlchemy 的会话缓存(Session Cache)是 ORM 框架的核心特性之一,对于理解和高效使用 SQLAlchemy 至关重要。这个缓存机制主要作用在会话(Session)层面,提供了对数据库交互的中间缓存层。以下是对 SQLAlchemy 会话缓存的详细解释:
什么是会话缓存?
-
一级缓存:会话缓存也被称为一级缓存。它自动存储在一个 SQLAlchemy Session 生命周期内加载的所有 ORM 对象。这意味着在会话期间,对同一个数据库实体的重复查询不会导致多次数据库请求。
-
自动化的工作流:当你通过一个会话查询数据库时,SQLAlchemy 首先检查这个对象是否已经在会话缓存中。如果是,它会直接从缓存中返回对象,而不是从数据库重新加载。
-
对象唯一性:在一个会话中,对于具有相同主键的实体,会话缓存确保只有一个唯一的对象实例。这有助于维护数据的一致性。
会话缓存的工作原理
当您使用 Session 对象查询数据库时,例如:
my_object = session.query(MyModel).filter_by(id=1).first()
-
如果 my_object 是首次被请求,它会被加载并存储在会话缓存中。
-
如果稍后在同一会话中再次查询相同的 MyModel 实例,SQLAlchemy 会直接从会话缓存中返回这个对象,而不是执行新的数据库查询。
会话缓存的好处
-
减少数据库查询:通过减少对数据库的重复查询,提高了应用性能。
-
数据一致性:在会话期间,对于同一对象的更改在整个会话中是一致的,避免了可能的数据不一致问题。
-
事务支持:会话缓存支持事务操作。当一个事务被回滚时,所有的会话缓存也会被回滚到事务开始之前的状态。
管理会话缓存
-
清空缓存:可以通过 session.expire_all() 清空会话缓存,这会使所有已加载的对象变为“过期”状态,下次访问这些对象的任何属性时,SQLAlchemy 会从数据库重新加载它们。
-
手动刷新:session.flush() 会将会话中的更改(如新对象或修改的对象)同步到数据库,但不会提交事务。这不会影响会话缓存中已有的对象。
注意事项
-
长期会话问题:在长期运行的会话中,会话缓存可能会导致内存占用增加,特别是在处理大量数据时。
-
数据过时问题:如果数据库中的数据在会话外被修改,会话缓存中的数据可能会过时。这种情况下,需要使用 expire、refresh 或 expire_all 方法来更新缓存数据。
代码展示
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("=====================================结束==================================================")
总结
会话缓存是 SQLAlchemy 中一个强大的特性,它提高了应用性能并支持复杂的事务管理。然而,合理地管理会话和缓存是确保应用稳定性和数据一致性的关键。
-
-
猜你喜欢
- 6天前(希尔顿2021活动)希尔顿集团618盛夏大促开启
- 6天前(四川率先建立“双定向”基层文化人才职称评审通道机制)四川率先建立“双定向”基层文化人才职称评审通道机制
- 6天前(安徽民航君澜大饭店装饰设计招标)集东方文化气息,品徽派隽美风韵----安徽民航君澜大饭店静待绽放
- 6天前(兵团猛进秦剧团持续开展“戏曲进校园”活动)兵团猛进秦剧团持续开展“戏曲进校园”活动
- 6天前(“为人民绽放——国家艺术基金优秀剧目展演”在合肥开幕)“为人民绽放——国家艺术基金优秀剧目展演”在合肥开幕
- 6天前(纳米比亚旅游报价)纳米比亚旅游局2024年中国推介会圆满落幕
- 6天前(上海迪士尼 夏天)酷爽夏日,奇妙相伴!来上海迪士尼度假区清凉入夏
- 6天前(辽宁新增6个国家4a级旅游景区有哪些)辽宁新增6个国家4A级旅游景区
- 6天前(“三天跨两城”催生租车新需求,神州租车清明跨城订单同比增长416%)“三天跨两城”催生租车新需求,神州租车清明跨城订单同比增长416%
- 6天前(北京香港航班动态查询)香港快运航空北京大兴新航线今日首航
网友评论
- 搜索
- 最新文章
- (2020广州车展哈弗)你的猛龙 独一无二 哈弗猛龙广州车展闪耀登场
- (哈弗新能源suv2019款)智能科技颠覆出行体验 哈弗重塑新能源越野SUV价值认知
- (2021款全新哈弗h5自动四驱报价)新哈弗H5再赴保障之旅,无惧冰雪护航哈弗全民电四驱挑战赛
- (海南航空现况怎样)用一场直播找到市场扩张新渠道,海南航空做对了什么?
- (visa jcb 日本)优惠面面俱到 JCB信用卡邀您畅玩日本冰雪季
- (第三届“堡里有年味·回村过大年”民俗花灯会活动)第三届“堡里有年味·回村过大年”民俗花灯会活动
- (展示非遗魅力 长安启源助力铜梁龙舞出征)展示非遗魅力 长安启源助力铜梁龙舞出征
- (阿斯塔纳航空公司)阿斯塔纳航空机队飞机数量增至50架
- (北京香港航班动态查询)香港快运航空北京大兴新航线今日首航
- (我在港航“呵护”飞机 每一次安全着陆就是最好的荣誉)我在港航“呵护”飞机 每一次安全着陆就是最好的荣誉
- 热门文章