1. 概述

本教程将演示如何使用Java Flight Recorder记录Hibernate生命周期执行过程中的事件。随后,我们将使用Oracle的JDK Mission Control工具分析记录的事件,深入理解Hibernate的内部执行机制。

2. Java Flight Recorder和JDK Mission Control简介

Java Flight Recorder (JFR) 是Oracle、OpenJDK和Oracle JDK的Hotspot虚拟机提供的底层监控代理。它专为Java应用程序性能监控设计。

JFR代理在应用运行期间记录来自JVM和Hibernate等框架的事件。这些事件被保存到文件中,可通过JDK Mission Control工具进行可视化分析。

3. 配置应用生成Hibernate-JFR事件

Hibernate ORM默认不生成Java Flight Recorder事件。要启用事件生成,需在pom.xml中添加hibernate-jfr依赖:

<dependency>
    <groupId>org.hibernate.orm</groupId>
    <artifactId>hibernate-jfr</artifactId>
    <version>6.4.4.Final</version>
</dependency>

⚠️ 注意:hibernate-jfr jar包仅从Hibernate 6.4开始提供

3.1. 配置示例Spring Boot应用

创建一个使用spring-data-jpaehcache作为Hibernate二级缓存的Spring Boot应用演示JFR事件。示例使用Spring Boot 3.1.5

应用使用H2数据库,配置如下:

spring:
  h2:
    console.enabled: true
  datasource:
    url: jdbc:h2:mem:hibernatejfr
    username: sa
    password: password
    driverClassName: org.h2.Driver
  jpa:
    database-platform: org.hibernate.dialect.H2Dialect
    defer-datasource-initialization: true
    show-sql: true # 打印SQL语句
    properties:
      hibernate:
        format_sql: true
        generate_statistics: true
        ## 启用JDBC批量插入
        jdbc.batch_size: 4
        order_inserts: true
        javax.cache.provider: org.ehcache.jsr107.EhcacheCachingProvider
        ## 启用二级缓存
        cache:
          region.factory_class: org.hibernate.cache.jcache.JCacheRegionFactory
          use_second_level_cache: true
          use_query_cache: true
      jakarta.persistence.sharedCache.mode: ENABLE_SELECTIVE

演示应用的类图结构如下:

示例应用类图

通过添加-XX:StartFlightRecording VM参数启动应用:

java -XX:StartFlightRecording=filename=myrecordingL2Cache.jfr -jar hibernatejfr-0.0.1-SNAPSHOT.jar

在IntelliJ中配置VM参数:

IntelliJ IDEA添加VM参数

启动流程:

  1. 启动应用
  2. 使用cURL或PostMan访问REST接口
  3. 停止应用
  4. 验证记录文件生成

✅ 测试场景:可通过maven-surefire-plugin在单元测试中启用JFR记录。

3.2. 日志配置

启用hibernate.generate_statistics可生成包含二级缓存命中和JDBC连接统计的日志。这些日志有助于验证二级缓存配置。

JFR启动时的关键日志:

[0.444s][info][jfr,startup] Started recording 1. No limit specified, using maxsize=250MB as default.
[0.444s][info][jfr,startup] 
[0.444s][info][jfr,startup] Use jcmd 27465 JFR.dump name=1 to copy recording data to file.

4. Hibernate JFR事件类型

hibernate-jfr通过SPI机制集成到Hibernate生命周期。核心流程:

  1. hibernate-core声明org.hibernate.event.spi.EventManager SPI接口
  2. hibernate-jfr实现该接口
  3. Hibernate检测到JFR包后自动注册事件监听器

hibernate-jfr定义的事件列表:

  • CacheGetEvent
  • CachePutEvent
  • DirtyCalculationEvent
  • FlushEvent
  • JdbcBatchExecutionEvent
  • JdbcConnectionAcquisitionEvent
  • JdbcConnectionReleaseEvent
  • JdbcPreparedStatementCreationEvent
  • JdbcPreparedStatementExecutionEvent
  • PartialFlushEvent
  • SessionClosedEvent
  • SessionOpenEvent

⚠️ 事件发布条件:

  • CacheGetEvent/CachePutEvent:仅当配置二级缓存时触发
  • JdbcBatchExecutionEvent:仅在批处理模式下执行JDBC查询时触发

事件属性示例(SessionOpenEvent):

SessionOpenEvent事件属性

关键分析属性:

  • ✅ 开始时间
  • ✅ 持续时间
  • ✅ 结束时间
  • ✅ 事件线程
  • ⚠️ 会话标识符(部分事件支持)

5. 使用JDK Mission Control分析JFR事件

5.1. 定位Hibernate ORM事件

启动JDK Mission Control后:

  1. 通过File > Open File打开JFR文件
  2. 忽略默认的自动分析页面
  3. 在"Outline"窗格的"Event Browser"中定位到"Event Types Tree > Hibernate ORM"

JMC事件浏览器

5.2. 分组相关事件

操作步骤:

  1. 右键点击"Hibernate ORM"节点
  2. 选择"Create New Page Based on the Selected Event Types"
  3. 重命名新页面(如"Hibernate Events")
  4. 在事件表中右键选择Group By > Event Thread

按线程分组事件

⚠️ 重要提示:在响应式/多线程场景下慎用线程分组,可能导致关联事件分散。

5.3. 基础事件分析

关键操作:

  1. 添加Total Duration列(右键表头 > Visible Columns > Total Duration
  2. 按总耗时排序识别瓶颈线程
  3. 按开始时间排序查看事件序列

分析示例:

事件分析结果

典型发现:

  • JDBC语句执行/创建耗时最长
  • 缓存操作次之
  • 可直接查看执行的SQL语句

6. 总结

本文完整介绍了:

  1. 使用JFR记录Hibernate事件的配置方法
  2. 通过JDK Mission Control分析事件的关键步骤
  3. 识别ORM层性能瓶颈的有效手段
  4. 事件序列与SQL执行的可视化方法

通过这些技术,开发者可以:

  • 精准定位Hibernate性能瓶颈
  • 理解ORM层内部执行流程
  • 验证二级缓存效果
  • 优化JDBC交互

示例代码及JFR文件可在GitHub仓库获取。


原始标题:Monitoring Hibernate Events With Java Flight Recorder | Baeldung