Spring+Hibernate场景下如何减少DB访问次数?缓存是唯一方式吗
减少Spring集成Hibernate场景下数据库访问次数的常用方法
- 合理利用Hibernate内置缓存机制
- 一级缓存(Session级缓存):默认自动开启,同一个Session内相同ID的实体查询只会触发1次DB查询。开发时注意同一事务内复用同一个Session,避免频繁创建销毁Session;批量操作时可适时调用
flush()+clear()方法清空缓存,避免内存溢出。 - 二级缓存(SessionFactory级缓存):属于全局共享缓存,适合改动频率低、访问频率高的实体类(比如基础数据字典),可搭配EHCache、Redis等缓存组件实现,需要根据业务特性配置合理的缓存过期、更新策略,避免脏数据产生。
- 查询缓存:针对固定条件的高频查询结果做缓存,需要和二级缓存搭配使用,开启时在对应查询方法上配置
setCacheable(true)即可。
- 一级缓存(Session级缓存):默认自动开启,同一个Session内相同ID的实体查询只会触发1次DB查询。开发时注意同一事务内复用同一个Session,避免频繁创建销毁Session;批量操作时可适时调用
- 优化查询逻辑,避免N+1查询问题
N+1是Hibernate开发中最常见的多余DB查询场景,可通过以下方案解决:- 关联查询时指定
fetch = FetchType.JOIN,或者在HQL中使用join fetch语法,一次性加载需要的关联实体 - 给需要批量加载的关联实体添加
@BatchSize注解,设置批量查询阈值,比如查询15个主实体时,关联的从实体会一次性批量查询,而不是每个主实体单独触发1次查询
- 关联查询时指定
- 批量操作优化
批量插入、更新、删除场景下,配置hibernate.jdbc.batch_size参数设置批量提交阈值,比如设置为20时,每攒够20条SQL就一次性提交给数据库,避免单条SQL单独提交的多次网络往返。大批量数据操作建议使用StatelessSession,绕过一级缓存的额外开销。 - 按需加载减少无效查询
不需要用到的关联实体保持默认懒加载策略,不要设置为立即加载;如果只需要实体的少数几个字段,优先用DTO投影查询,只查询需要的字段,不要全量查询整个实体。 - 业务层与数据库层配合优化
高频的统计、报表类查询,提前做好预汇总表,业务直接查询汇总表,不需要每次都执行多表关联聚合查询;给高频查询的条件字段添加合理索引,降低单查询的执行耗时。
缓存是否是唯一实现方式的说明
一级缓存、二级缓存不是减少数据库访问次数的唯一实现方式
上述的查询逻辑优化、批量操作、投影查询、预汇总表等方案都可以从不同维度减少DB访问次数,实际业务中一般是多种方案搭配使用,不会单纯依赖缓存。缓存更适合读多写少、对数据一致性容忍度稍高的场景,对于写操作多、数据一致性要求极高的场景,查询优化等方案的适配性更高。
内容的提问来源于stack exchange,提问作者Sagara S.Dev
相关产品推荐
相关产品推荐

