簡體   English   中英

嘗試使用Spring / JPA / Hikari在我的代碼中查找數據庫連接泄漏

[英]trying to find db connection leak in my code, using Spring / JPA / Hikari

我有一個Spring Web應用程序的問題,它定期遇到從我的連接池獲取連接時出錯。 最后在日志中我看到如下條目:

  • 引起:javax.persistence.PersistenceException:org.hibernate.exception.JDBCConnectionException:無法獲取JDBC連接
  • 引起:java.sql.SQLTransientConnectionException:HikariPool-1 - 連接不可用,請求在30000ms后超時。

只有恢復的方法我發現它一旦遇到這一點就重啟Tomcat。

我認為最可能的解釋是我在某處某些代碼沒有正確清理它的連接 - 將其返回給Hikari,留下一些東西讓Spring無法清理它等等。

要解決問題,我已將hikari配置leakDetectionThreshold設置為5000毫秒並啟用了日志記錄。 之后,我看到日志條目如

2018-04-24 19:53:56 WARN  ProxyLeakTask:87 - Connection leak detection 
triggered for org.postgresql.jdbc.PgConnection@664ec666, stack trace 
follows
java.lang.Exception: Apparent connection leak detected
    at org.hibernate.engine.jdbc.connections.internal.DatasourceConnectionProviderImpl.getConnection(DatasourceConnectionProviderImpl.java:122)
    at org.hibernate.internal.NonContextualJdbcConnectionAccess.obtainConnection(NonContextualJdbcConnectionAccess.java:35)
    at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.acquireConnectionIfNeeded(LogicalConnectionManagedImpl.java:99)
    at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.getPhysicalConnection(LogicalConnectionManagedImpl.java:129)
    at org.hibernate.engine.jdbc.internal.StatementPreparerImpl.connection(StatementPreparerImpl.java:47)
    at org.hibernate.engine.jdbc.internal.StatementPreparerImpl$5.doPrepare(StatementPreparerImpl.java:146)
    at org.hibernate.engine.jdbc.internal.StatementPreparerImpl$StatementPreparationTemplate.prepareStatement(StatementPreparerImpl.java:172)
    at org.hibernate.engine.jdbc.internal.StatementPreparerImpl.prepareQueryStatement(StatementPreparerImpl.java:148)
    at org.hibernate.loader.Loader.prepareQueryStatement(Loader.java:1940)
    at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1909)
    at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1887)
    at org.hibernate.loader.Loader.doQuery(Loader.java:932)
    at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:349)
    at org.hibernate.loader.Loader.doList(Loader.java:2615)
    at org.hibernate.loader.Loader.doList(Loader.java:2598)
    at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2430)
    at org.hibernate.loader.Loader.list(Loader.java:2425)
    at org.hibernate.loader.custom.CustomLoader.list(CustomLoader.java:335)
    at org.hibernate.internal.SessionImpl.listCustomQuery(SessionImpl.java:2129)
    at org.hibernate.internal.AbstractSharedSessionContract.list(AbstractSharedSessionContract.java:981)
    at org.hibernate.query.internal.NativeQueryImpl.doList(NativeQueryImpl.java:147)
    at org.hibernate.query.internal.AbstractProducedQuery.list(AbstractProducedQuery.java:1398)
    at org.hibernate.query.internal.AbstractProducedQuery.getSingleResult(AbstractProducedQuery.java:1444)
    at sun.reflect.GeneratedMethodAccessor191.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.springframework.orm.jpa.SharedEntityManagerCreator$DeferredQueryInvocationHandler.invoke(SharedEntityManagerCreator.java:379)
    at com.sun.proxy.$Proxy163.getSingleResult(Unknown Source)
    at com.mycompany.web.jpa.util.DBHelper.getPagedMappedDbResults(DBHelper.java:76)
    at com.mycompany.web.jpa.repository.TaskRepositoryImpl.findTaskDetailsByStepIdAndIdIn(TaskRepositoryImpl.java:245)
......

所以它正在檢測可能的泄漏。 我猜想可能是假陽性? 但這也是我的應用程序中唯一一個在Spring應用程序中經常使用的標准服務/存儲庫模式之外進行數據庫訪問的類,因此它似乎是一個可能的罪魁禍首,而且它是我目前最好的領導者。

無論如何,我在跟蹤中看到的最后一段非庫代碼(即我寫的東西,所以最有可能是泄漏的原因!)是我的DBHelper :: getPagedMappedDbResults方法,相關位包括在這里:

    Query q = entityManager.createNativeQuery(countQueryText);
    setQueryParameters(q, parameters);
    long numActualResults = 0;
    try {
        numActualResults = ((Number)q.getSingleResult()).longValue(); // line 76
    } catch (Exception e) {
        System.out.println("just in case: " + e);
    }

所以基本上我從我的EntityManager實例創建一個Query對象,設置一些參數,並運行它來獲得一些結果。

當我完成它時,我是否需要使用Query對象? q.cleanup()? 我從閱讀文檔中看不到這樣的東西,但是我沒有在這個資源上做好管家嗎?

entityManager本身是從@Autowired注釋創建的。 我的理解是,如果我沒有“新”它來實例化它,而是讓Spring框架自動裝配它,那么Spring將做任何必要的清理工作。 是對的嗎? 或者在使用entityManager后是否需要進行一些清理?

版本細節:

  • Tomcat 8 / Java 8
  • Spring 5.0.0.RELEASE
  • Spring Data Kay-RELEASE
  • Hibernate 5.2.3.Final
  • Hikari 2.4.5

任何建議或建議將不勝感激,謝謝!

什么是查詢? 它很重嗎? 也許你在這里遇到僵局? 連接管理看起來很好。 您沒有明確獲取連接,因此無需釋放它。 查詢可能會長時間運行,因此Hibernate無法完成它並釋放連接。

此外,您可以檢查數據庫端的打開連接數。 在這方面做一些分析。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM