当前位置: 首页 > article >正文

Spring Boot 项目中常用的 ORM 框架 (JPA/Hibernate) 在性能方面有哪些需要注意的点?

在 Spring Boot 项目中使用 JPA (Java Persistence API) / Hibernate (作为 JPA 的默认实现) 时,性能是一个非常关键的考量点。虽然 ORM 极大地简化了数据库交互,但如果不注意,很容易引入性能瓶颈。以下是一些关键的性能注意事项:

  1. N+1 查询问题 (N+1 Select Problem)

    • 问题描述: 这是最常见也是最严重的性能问题之一。当你查询一个实体列表(1次查询),然后在循环中访问每个实体的延迟加载(Lazy Loaded)关联对象时,会为每个实体额外触发一次(或多次)查询(N次查询)。
    • 解决方案:
      • Fetch Joins (JPQL/HQL): 在 JPQL 查询中使用 JOIN FETCH 来显式指定在初始查询中就加载关联对象。 SELECT DISTINCT e FROM Employee e JOIN FETCH e.department
      • Entity Graphs (@EntityGraph): 使用 JPA 2.1 引入的 @EntityGraph 注解(或动态创建 EntityGraph),可以在运行时或编译时定义需要一起加载的关联属性图。这比 JOIN FETCH 更灵活,尤其是在 CrudRepository 接口方法上使用时。
      • Batch Fetching (@BatchSize): 在关联属性或实体类上使用 Hibernate 的 @BatchSize(size=N) 注解。这不会消除 N 次查询,但会将它们分批执行(例如,一次查询加载 N 个关联对象),显著减少查询次数。可以在 application.properties/yml 中全局配置 spring.jpa.properties.hibernate.default_batch_fetch_size=...
      • Subselect Fetching (@Fetch(FetchMode.SUBSELECT)): 对于集合关联,使用 Hibernate 的 @Fetch(FetchMode.SUBSELECT)。它会在加载主实体列表后,通过一个子查询(WHERE main_entity_id IN (...))一次性加载所有关联的集合。
  2. 加载策略 (Fetching Strategies: Eager vs. Lazy)

    • 问题描述:
      • Eager Loading (急加载): 如果关联设置为 FetchType.EAGER@ManyToOne, @OneToOne 的默认值),关联对象会随主实体一起加载,即使你当前不需要它们。这可能导致查询加载过多不必要的数据,拖慢速度并消耗更多内存。
      • Lazy Loading (懒加载): 如果设置为 FetchType.LAZY@OneToMany, @ManyToMany 的默认值),关联对象只在首次访问时才加载。这通常更好,但需要注意 N+1 问题,并且如果在事务关闭后访问懒加载属性,会抛出 LazyInitializationException
    • 建议:
      • 优先使用 Lazy Loading: 对于绝大多数关联,尤其是集合关联,坚持使用 FetchType.LAZY
      • 按需加载: 结合前面提到的 Fetch Joins, Entity Graphs 或 Batch Fetching 来解决特定场景下需要预先加载数据的问题。
      • 理解默认值: 注意 @ManyToOne@OneToOne 默认是 Eager,通常建议显式改为 fetch = FetchType.LAZY
  3. 投影 (Projections)

    • 问题描述: 经常只需要查询实体的一部分字段,但默认情况下 findById, findAll 等方法会加载整个实体及其所有(非懒加载)属性,这可能涉及很多不必要的列和数据传输。
    • 解决方案:
      • DTO 投影 (JPQL/HQL): 使用 JPQL 的构造函数表达式 SELECT new com.example.MyDTO(e.id, e.name) FROM Employee e WHERE ... 直接将查询结果映射到 DTO。
      • 接口投影 (Spring Data JPA): 定义一个只包含所需 getter 方法的接口,Spring Data JPA 会自动实现它,只查询对应的列。
      • Specification / Criteria API: 使用 JPA Criteria API 或 Spring Data JPA Specifications 构建查询时,可以指定只选择特定的列。
      • Native Queries: 如果需要非常精细的控制或复杂的 SQL,可以使用原生 SQL 查询并映射结果。
  4. 缓存 (Caching)

    • 一级缓存 (Session Cache / Persistence Context Cache):
      • 作用: 在同一个 Hibernate Session(通常对应一个事务)内有效。对于通过 ID 加载的实体,如果 Session 缓存中已存在,则直接返回缓存中的对象,避免重复查询数据库。对实体的修改也会在缓存中进行,最后通过 Flush 操作同步到数据库。
      • 注意: 它的生命周期与 Session/Transaction 绑定,无法跨事务共享。需要理解其工作原理,避免因 Session 过大导致内存问题(见下一条)。
    • 二级缓存 (Second-Level Cache / Shared Cache):
      • 作用: 跨 Session/Transaction 共享的缓存,可以缓存实体数据、集合 ID 等。对于经常读取且不经常修改的数据(如配置信息、基础数据)非常有效,可以显著减少数据库负载。
      • 配置: 需要显式启用和配置(选择缓存提供商如 EhCache, Caffeine, Redis 等),并在实体或属性上使用 @Cacheable 等注解。
      • 注意: 会增加应用复杂性(缓存同步、失效策略),可能遇到脏数据问题。需要仔细评估是否需要以及如何配置。
    • 查询缓存 (Query Cache):
      • 作用: 缓存 JPQL/HQL 查询的结果集。当执行相同的查询(包括参数)时,可以直接从缓存返回结果。
      • 配置: 需要显式启用,并为需要缓存的查询设置 query.setHint("org.hibernate.cacheable", true);
      • 注意: 查询缓存的失效比较复杂,当涉及的任何表发生更改时,相关的查询缓存项通常会失效。适用于结果集相对稳定且查询开销大的场景。
  5. 会话管理 (Session Management)

    • 问题描述: 在单个事务(或 Session)中加载和管理过多的实体对象会消耗大量内存,并且在事务提交(Flush)时,Hibernate 需要对所有受管(Managed)状态的实体进行脏检查(Dirty Checking),这可能非常耗时。
    • 解决方案:
      • 保持事务简短: 尽量让事务覆盖最小必要的操作范围。
      • 分页查询: 对于大量数据的列表,务必使用分页(Spring Data JPA 的 Pageable)。
      • 定期 Flush 和 Clear: 在处理大量数据的批处理任务中,可以手动调用 entityManager.flush() 将变更同步到数据库,然后调用 entityManager.clear() 清除持久化上下文(一级缓存),释放内存,让后续加载的对象重新被管理。
      • 只读事务: 对于纯读取操作,使用 @Transactional(readOnly = true)。这可以给数据库和 Hibernate 一些优化提示(例如,Hibernate 可能禁用脏检查,数据库可能使用更优的锁策略)。
      • Stateless Session (Hibernate Specific): 对于纯粹的、无状态的批量插入/更新/删除操作,可以考虑使用 Hibernate 的 StatelessSession,它没有一级缓存和脏检查,性能更高,但功能受限。
  6. 批量操作 (Batch Operations)

    • 问题描述: 逐条插入、更新或删除大量数据会导致大量的数据库交互和网络往返,效率低下。
    • 解决方案:
      • JDBC Batching: 配置 Hibernate 启用 JDBC 批处理。在 application.properties/yml 中设置 spring.jpa.properties.hibernate.jdbc.batch_size=...(例如 20-50)。Hibernate 会将相同类型的 DML 语句分组,一次性发送给数据库。
      • 设置 order_insertsorder_updates: 设置 spring.jpa.properties.hibernate.order_inserts=truespring.jpa.properties.hibernate.order_updates=true 可以让 Hibernate 对 DML 语句按表排序后再进行批处理,进一步提高效率(尤其是在有外键约束时)。
      • 对于非常大的批量操作: 可能需要考虑使用 JPA 本身不太擅长的更底层技术,如直接使用 JdbcTemplate 的批处理,或者数据库特定的批量加载工具。
  7. 查询优化与索引

    • 分析生成的 SQL: 开启 Hibernate 的 SQL 日志 (spring.jpa.show-sql=true, spring.jpa.properties.hibernate.format_sql=true) 或使用 p6spy 等工具,检查 ORM 生成的 SQL 是否符合预期,是否高效。
    • 数据库索引: 确保数据库表有合适的索引,特别是针对查询条件(WHERE 子句)、连接条件(JOIN ON)和排序字段(ORDER BY)。这是数据库层面的优化,但对 ORM 性能至关重要。
    • 避免笛卡尔积: 在关联查询中要小心,确保使用了正确的连接条件,避免产生不必要的笛卡尔积。
    • 优化 JPQL/Criteria 查询: 编写高效的 JPQL 或 Criteria API 查询,避免不必要的子查询或复杂的逻辑。有时原生 SQL (Native Query) 可能更优,但会牺牲可移植性。
  8. 映射设计

    • 选择合适的继承策略: @Inheritance 策略(SINGLE_TABLE, JOINED, TABLE_PER_CLASS)对性能有不同影响。SINGLE_TABLE 查询快但可能浪费空间且不利于非空约束;JOINED 规范但查询涉及连接;TABLE_PER_CLASS 查询复杂(UNION ALL)。根据实际情况权衡。
    • 避免不必要的 LOB 加载: 懒加载 LOB (@Lob, @Basic(fetch = FetchType.LAZY)) 类型字段,除非确实需要。
    • 集合映射: 使用 @OrderColumn 来维护 List 顺序会带来额外的更新开销。如果不需要严格的数据库层面排序,可考虑使用 @OrderBy(在加载时排序)或在 Java 代码中排序。
  9. 配置调优

    • 连接池: Spring Boot 默认使用 HikariCP,通常性能很好。根据应用负载调整连接池大小(spring.datasource.hikari.maximum-pool-size 等)。
    • JDBC Fetch Size: spring.jpa.properties.hibernate.jdbc.fetch_size 可以控制 ResultSet 一次从数据库获取多少行数据到 JDBC Driver,适当调整可能对大数据量查询有帮助。
  10. 监控与分析

    • 使用监控工具: 利用 Spring Boot Actuator 的 metrics 端点、JMX、或者 APM 工具(如 SkyWalking, Pinpoint, Dynatrace, New Relic)来监控数据库交互时间、查询频率、缓存命中率等。
    • Hibernate Statistics: 启用 Hibernate 统计信息 (spring.jpa.properties.hibernate.generate_statistics=true) 可以提供关于 Session、缓存、查询等方面的详细性能数据,有助于定位瓶颈。

总结:

JPA/Hibernate 提供了强大的功能,但也隐藏了许多性能陷阱。关键在于理解其工作原理,特别是懒加载、N+1 问题、缓存机制和会话管理。通过合理的配置、优化的查询编写(JPQL/EntityGraph/Projections)、有效的缓存策略以及必要的监控和分析,可以在享受 ORM 便利的同时,构建出高性能的 Spring Boot 应用。我们要明白一点,没有银弹,需要根据具体的业务场景和数据特点进行权衡和优化。

相关文章:

Spring Boot 项目中常用的 ORM 框架 (JPA/Hibernate) 在性能方面有哪些需要注意的点?

在 Spring Boot 项目中使用 JPA (Java Persistence API) / Hibernate (作为 JPA 的默认实现) 时,性能是一个非常关键的考量点。虽然 ORM 极大地简化了数据库交互,但如果不注意,很容易引入性能瓶颈。以下是一些关键的性能注意事项:…...

基于大模型的大肠癌全流程预测与诊疗方案研究报告

目录 一、引言 1.1 研究背景与意义 1.2 研究目的与创新点 二、大模型技术概述 2.1 大模型原理与架构 2.2 大模型在医疗领域的应用现状 三、术前风险预测与准备 3.1 术前风险预测指标 3.2 大模型预测方法与结果 3.3 基于预测结果的术前准备方案 四、术中风险预测与应…...

解决DeepSeek部署难题:提升效率与稳定性的关键策略

DeepSeek 部署中常见问题及对应解决方案 随着大模型技术的快速发展,DeepSeek 作为国内领先的大语言模型之一,广泛应用于自然语言处理、智能客服、内容生成等多个领域。 然而,在实际部署过程中,许多开发者和企业会遇到一系列挑战&a…...

AI进行提问、改写、生图、联网搜索资料,嘎嘎方便!

极客侧边栏-AI板块 目前插件内已接入DeepSeek-R1满血版、Qwen3满血版 、豆包/智谱最新发布的推理模型以及各种顶尖AI大模型,并且目前全都可以免费不限次数使用,秒回不卡顿,联网效果超好! 相比于市面上很多AI产品,极客…...

GStreamer开发笔记(四):ubuntu搭建GStreamer基础开发环境以及基础Demo

若该文为原创文章,转载请注明原文出处 本文章博客地址:https://blog.csdn.net/qq21497936/article/details/147714800 长沙红胖子Qt(长沙创微智科)博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、O…...

2021年认证杯SPSSPRO杯数学建模A题(第二阶段)医学图像的配准全过程文档及程序

2021年认证杯SPSSPRO杯数学建模 A题 医学图像的配准 原题再现: 图像的配准是图像处理领域中的一个典型问题和技术难点,其目的在于比较或融合同一对象在不同条件下获取的图像。例如为了更好地综合多种信息来辨识不同组织或病变,医生可能使用…...

CV中常用Backbone-3:Clip/SAM原理以及代码操作

前面已经介绍了简单的视觉编码器,这里主要介绍多模态中使用比较多的两种backbone:1、Clip;2、SAM。对于这两个backbone简单介绍基本原理,主要是讨论使用这个backbone。 1、CV中常用Backbone-2:ConvNeXt模型详解 2、CV中…...

RPC 协议详解、案例分析与应用场景

一、RPC 协议原理详解 RPC 协议的核心目标是让开发者像调用本地函数一样调用远程服务,其实现过程涉及多个关键组件与流程。 (一)核心组件 客户端(Client):发起远程过程调用的一方,它并不关心调…...

dify-plugin-daemon的.env配置文件

源码位置:dify-plugin-daemon\.env 本文使用dify-plugin-daemon v0.1.0版本,主要总结了dify-plugin-daemon\.env配置文件。为了本地调试方便,采用本地运行时环境WSL2Ubuntu22.04方式运行dify-plugin-daemon服务。 一.服务器基本配置 服务器…...

【Python】开发工具uv

文章目录 1. uv install1.1 下载安装脚本来安装1.2 使用pipx安装uv1.3 补充 2. 考虑在离线系统上安装uv2.1 下载并上传安装包2.2 用户级安装uv(~/.local/bin/)2.3 补充 3. uv 管理Python解释器4. uv 管理依赖5. uv运行代码5.1 uv不在项目下执行脚本5.2 u…...

《技术择时,价值择股》速读笔记

文章目录 书籍信息概览技术择时价值择股投资策略投资心态 书籍信息 书名:《技术择时,价值择股:A股投资实战笔记》 作者:二十八画生 概览 技术择时 三种简单方法,教你买在起涨点 趋势行情中的“买点”判断&#xff…...

Python可视化设计原则

在数据驱动的时代,可视化不仅是结果的呈现方式,更是数据故事的核心载体。Python凭借其丰富的生态库(Matplotlib/Seaborn/Plotly等),已成为数据可视化领域的主力工具。但工具只是起点,真正让图表产生价值的&…...

SAP重塑云ERP应用套件

在2025年Sapphire大会上,SAP正式发布了其云ERP产品的重塑计划,推出全新“Business Suite”应用套件,并对供应链相关应用进行AI增强升级。这一变革旨在简化新客户进入SAP生态系统的流程,同时为现有客户提供更加统一、智能和高效的业…...

2025.5.25总结

今天早上刷了会手机,然后下午去刷了一道科目一,限时训练3.5h。遗憾的是,这周只刷了一道题,并没有达成每周两道的目标。 其次,一天下来跟平时的节假日一样,有些小压抑。我也察觉到了自己的情绪。烦心事无非…...

(九)PMSM驱动控制学习---无感控制之高阶滑膜观测器

在之前的文章中,我们介绍了永磁同步电机无感控制中的滑模观测器,但是同时我们也认识到了他的缺点:因符号函数带来的高频切换分量,使用低通滤波器引发相位延迟;在本篇文章,我们将会介绍高阶滑模观测器的无感…...

6个跨境电商独立站平台

1. WP最主题(WPZUI) 官网:http://www.wpzui.com 简介: WP最主题专注于专业WordPress主题开发定制,致力于为用户提供高质量、高性能的WordPress主题。其主题设计注重用户体验和SEO优化,适用于多种网站类型,包括企业站…...

电子电路:电学都有哪些核心概念?

电子是基本粒子,带负电荷。电荷是物质的一种属性,电子带有负电荷,而质子带有正电荷。电荷的单位是库仑。 电流呢,应该是指电荷的流动,单位是安培,也就是库仑每秒。所以电流其实就是电荷在导体中的移动形成的。比如,当电子在导线中流动时,就形成了电流。不过要注意,传…...

SQL进阶之旅 Day 2:基础查询优化技巧

【SQL进阶之旅 Day 2】基础查询优化技巧 开篇:为什么需要基础查询优化? 在SQL学习的旅程中,掌握基础查询优化是迈向专业数据库开发的关键一步。随着数据量的爆炸式增长,简单的SELECT语句已经无法满足现代应用对性能的要求。今天…...

时序数据库 TDengine × Superset:一键构建你的可视化分析系统

如果你正在用 TDengine 管理时序数据,写 SQL 查询没问题,但一到展示环节就犯难——图表太基础,交互不够,甚至连团队都看不懂你辛苦分析的数据成果?别担心,今天要介绍的这个组合,正是为你量身打造…...

一键化部署

好的,我明白了。你希望脚本变得更简洁,主要负责: 代码克隆:从 GitHub 克隆你的后端和前端项目,并在克隆前确保目标目录为空。文件复制:将你预先准备好的 Dockerfile (后端和前端各一个)、前端的 nginx.con…...

Win 系统 conda 如何配置镜像源

通过命令添加镜像源(推荐) 以 清华源 为例,依次执行以下命令: # 添加主镜像源 conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main # 添加免费开源镜像源 conda config --add channels http…...

Devicenet主转Profinet网关助力改造焊接机器人系统智能升级

某汽车零部件焊接车间原有6台焊接机器人(采用Devicenet协议)需与新增的西门子S7-1200 PLC(Profinet协议)组网。若更换所有机器人控制器或上位机系统,成本过高且停产周期长。 《解决方案》 工程师选择稳联技术转换网关…...

《STL--list的使用及其底层实现》

引言: 上次我们学习了容器vector的使用及其底层实现,今天我们再来学习一个容器list, 这里的list可以参考我们之前实现的单链表,但是这里的list是双向循环带头链表,下面我们就开始list的学习了。 一:list的…...

whisper相关的开源项目 (asr)

基于 Whisper(OpenAI 的开源语音识别模型)的开源项目有很多,涵盖了不同应用场景和优化方向。以下是一些值得关注的项目: 1. 核心工具 & 增强版 Whisper OpenAI Whisper 由 OpenAI 开源的通用语音识别模型,支持多语…...

python的pip怎么配置的国内镜像

以下是配置pip国内镜像源的详细方法: 常用国内镜像源列表 清华大学:https://pypi.tuna.tsinghua.edu.cn/simple阿里云:https://mirrors.aliyun.com/pypi/simple中科大:https://pypi.mirrors.ustc.edu.cn/simple华为云&#xff1…...

PCB 通孔是电容性的,但不一定是电容器

哼?……这是什么意思?…… 多年来,流行的观点是 PCB 通孔本质上是电容性的,因此可以用集总电容器进行建模。虽然当信号的上升时间大于或等于过孔不连续性延迟的 3 倍时,这可能是正确的,但我将向您展示为什…...

领域驱动设计与COLA框架:从理论到实践的落地之路

目录 引言 DDD核心概念 什么是领域驱动设计 DDD的核心概念 1. 统一语言(Ubiquitous Language) 2. 限界上下文(Bounded Context) 3. 实体(Entity)与值对象(Value Object) 4. 聚…...

公有云AWS基础架构与核心服务:从概念到实践

🔥「炎码工坊」技术弹药已装填! 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 (初学者技术专栏) 一、基础概念 定义:AWS(Amazon Web Services)是亚马逊提供的云计算服务&a…...

Python60日基础学习打卡D35

import torch import torch.nn as nn import torch.optim as optim from sklearn.datasets import load_iris from sklearn.model_selection import train_test_split from sklearn.preprocessing import MinMaxScaler import time import matplotlib.pyplot as plt# 设置GPU设…...

Python经典算法实战

在编程的世界里,算法是解决问题的灵魂,而Python以其简洁优雅的语法成为实现算法的理想语言。无论你是初学者还是有一定经验的开发者,《Python经典算法实战》都能带你深入算法的殿堂,从理论到实践,一步步构建起扎实的编…...