关于createQuery偶发could not prepare statement异常的原因排查请求
间歇性出现"could not prepare statement"异常的排查思路
你遇到的是Hibernate执行createQuery时间歇性抛出could not prepare statement异常,底层根源是Connection is closed,只有10%的场景会触发,这个偶发问题确实挺棘手的,我来帮你梳理下可能的原因和排查方向:
问题代码
Session session = DB.getInstance().getSession(Id); DesiredObject = (DesiredObject) session.createQuery( "from DesiredTable where Id = :id") .setParameter("id", Id).uniqueResult();
完整堆栈信息
Caused by: org.hibernate.exception.GenericJDBCException: could not prepare statement at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:47) at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:113) at org.hibernate.engine.jdbc.internal.StatementPreparerImpl$StatementPreparationTemplate.prepareStatement(StatementPreparerImpl.java:186) at org.hibernate.engine.jdbc.internal.StatementPreparerImpl.prepareQueryStatement(StatementPreparerImpl.java:151) at org.hibernate.loader.Loader.prepareQueryStatement(Loader.java:2104) at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:2034) at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:2012) at org.hibernate.loader.Loader.doQuery(Loader.java:953) at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:354) at org.hibernate.loader.Loader.doList(Loader.java:2815) at org.hibernate.loader.Loader.doList(Loader.java:2797) at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2629) at org.hibernate.loader.Loader.list(Loader.java:2624) at org.hibernate.loader.hql.QueryLoader.list(QueryLoader.java:506) at org.hibernate.hql.internal.ast.QueryTranslatorImpl.list(QueryTranslatorImpl.java:396) at org.hibernate.engine.query.spi.HQLQueryPlan.performList(HQLQueryPlan.java:219) at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1396) at org.hibernate.query.internal.AbstractProducedQuery.doList(AbstractProducedQuery.java:1558) at org.hibernate.query.internal.AbstractProducedQuery.list(AbstractProducedQuery.java:1526) ... 14 more Caused by: java.sql.SQLException: Connection is closed at com.zaxxer.hikari.pool.ProxyConnection$ClosedConnection.lambda$getClosedConnection$0(ProxyConnection.java:489) at com.sun.proxy.$Proxy15.prepareStatement(Unknown Source) at com.zaxxer.hikari.pool.ProxyConnection.prepareStatement(ProxyConnection.java:311) at com.zaxxer.hikari.pool.HikariProxyConnection.prepareStatement(HikariProxyConnection.java) at org.hibernate.engine.jdbc.internal.StatementPreparerImpl$5.doPrepare(StatementPreparerImpl.java:149) at org.hibernate.engine.jdbc.internal.StatementPreparerImpl$StatementPreparationTemplate.prepareStatement(StatementPreparerImpl.java:176)
可能的原因及排查方向
- 连接池与数据库超时配置不匹配:从堆栈能看到用的是HikariCP,如果你的
idleTimeout或maxLifetime配置过短,而数据库端的连接超时(比如MySQL的wait_timeout)比连接池设置的更长,就会出现连接池认为连接还可用,但数据库已经把闲置连接关掉的情况。只有当刚好拿到这种失效连接时,才会触发异常,所以是间歇性的。 - Session管理逻辑有漏洞:你的
DB.getInstance().getSession(Id)方法如果存在Session复用逻辑(比如同一个Id对应的Session被多次获取却没正确重置/关闭),可能导致Session持有的连接已经被归还到池或失效,后续用这个Session执行查询时就会拿到关闭的连接。 - 连接泄漏问题:如果某些异常分支里漏掉了
session.close()或者事务的commit/rollback()操作,会导致连接池里的连接被长期占用直到超时回收。当连接池可用连接不足时,可能会拿到刚被回收的失效连接,引发异常。 - 连接池未开启连接有效性检测:如果HikariCP没有配置
connectionTestQuery(比如select 1),连接池在分配连接前不会验证连接是否可用。当数据库因为负载、网络抖动主动关闭了部分空闲连接,连接池无法提前发现,就会出现偶发的连接关闭异常。 - Session线程安全问题:Hibernate的Session本身不是线程安全的,如果
getSession(Id)返回的Session被多个线程共享,可能出现一个线程关闭了连接,另一个线程还在使用这个连接执行查询的情况,从而抛出连接已关闭的异常。
内容的提问来源于stack exchange,提问作者dreambigcoder
相关产品推荐
相关产品推荐

