bigywater.tech
Spring · 92

Open-In-View:数据库连接被占到响应结束

启动日志里的 open-in-view 警告到底在警告什么?为什么「查询早就结束了」连接还没还?关了会出什么问题?连接池小的时候它会把吞吐拖低多少?这篇在 Spring Boot 4.0.8、HikariCP、MySQL 上用 2 个连接的池实测。

1 → 0
查库返回之后活动连接数:open-in-view 默认是 1,关闭后是 0
60 vs 270
2 个连接、10 个并发、8 秒内的成功请求数:open-in-view 默认与关闭
LazyInitializationException
关闭 open-in-view 之后,控制器里访问懒加载集合会抛这个异常

连接被占多久

实测 · 本机执行输出
  启动日志里的 open-in-view 警告:LOG WARN o.s.b.j.a.JpaBaseConfiguration$JpaWebConfiguration - spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning
  GET /probe?ms=600 → 查库之前活动连接=0,repo.findById 返回之后=1,再睡 600 ms 之后=1
  显式写 spring.jpa.open-in-view=true:启动日志里的警告条数 0
  GET /probe?ms=600 → 查库之前活动连接=0,repo.findById 返回之后=1,再睡 600 ms 之后=1
  spring.jpa.open-in-view=false:启动日志里的警告条数 0
  GET /probe?ms=600 → 查库之前活动连接=0,repo.findById 返回之后=0,再睡 600 ms 之后=0

打开时连接从第一次查询持有到请求结束;关闭后事务一结束就还给池。

懒加载

实测 · 本机执行输出
  open-in-view=true:GET /lazy → HTTP 200 books.size()=3
    日志里的异常行:(没有)
  open-in-view=false:GET /lazy → HTTP 500 {"timestamp":"2026-10-20T03:34:17.434Z","status":500,"error":"Internal Server Error","path":"/lazy"}
    日志里的异常行:LOG ERROR o.a.c.c.C.[.[.[/].[dispatcherServlet] - Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed: org.hibernate.LazyInitializationException: Cannot lazily initi

打开时控制器里能访问懒加载集合;关闭后抛 LazyInitializationException。

对吞吐的影响

实测 · 本机执行输出
  open-in-view=true:成功 60 个(7.5 个/秒),失败 17 个 {'500': 17};成功请求的延迟 p50 1225 ms、p99 1267 ms
    服务端日志里的一行:LOG WARN org.hibernate.orm.jdbc.error - HikariPool-1 - Connection is not available, request timed out after 1005ms (total=2, active=2, idle=0, waiting=7)
  open-in-view=false:成功 270 个(33.8 个/秒),失败 0 个 ;成功请求的延迟 p50 307 ms、p99 313 ms

池小时打开会让连接成为瓶颈:吞吐低约 4.5 倍,还有 HTTP 500。

分步演示

Open-In-View
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / OpenJDK 21.0.12(Homebrew) / Spring Boot 4.0.8(Spring Framework 7.0.9、Tomcat 11.0.24) / Spring Cloud 2025.1.3;用 javac 编译、java 直接运行,依赖由 Maven 从 Maven Central 解析;数字每次运行会有小幅抖动(Hibernate 7、HikariCP 随 spring-boot-starter-data-jpa;MySQL 是本机自己起的 26.7.0 实例)。HikariCP maximum-pool-size=2、minimum-idle=2、connection-timeout=1000 ms,其余默认;活动连接数取自 HikariPoolMXBean.getActiveConnections();压测用 10 个 Python 线程循环请求 8 秒,每个请求 repo.findById(1L) 之后 Thread.sleep(300 ms);Tomcat 线程池为默认值
    • 没有验证:池更大、请求更慢时的临界点;外层带 @Transactional 的情形下(连接本来就占用到事务结束);JTA;读写分离或多数据源下 OSIV 对多个 EntityManager 的影响;Spring Data 的 @Transactional(readOnly) 对连接释放时机的影响;连接被持有的具体机制(Hibernate 的 connection handling mode,我只观察到结果);HTTP 500 在 connection-timeout 更长时的表现
    京ICP备2026067502号-1京公网安备11010502063487号