2016-12-19 95 views
3

我只是試圖簡化我的問題在一個小小的案例應用程序。
看起來連接直到線程完成纔會關閉。 Check this out春季數據庫負載測試:如何釋放連接

相關性的信息:

Servlet引擎:的Apache Tomcat/8.5.5
JPA提供商:休眠

我的pom.xml:

<?xml version="1.0" encoding="UTF-8"?> 
<project xmlns="http://maven.apache.org/POM/4.0.0" 
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 
    <modelVersion>4.0.0</modelVersion> 

    <groupId>...</groupId> 
    <artifactId>***-service</artifactId> 
    <version>0.0.1</version> 
    <packaging>jar</packaging> 

    <name>...</name> 
    <description>...</description> 

    <parent> 
     <groupId>org.springframework.boot</groupId> 
     <artifactId>spring-boot-starter</artifactId> 
     <version>1.4.1.RELEASE</version> 
    </parent> 

    <properties> 
     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 
     <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> 
     <java.version>1.8</java.version> 
     <spring.cloud.release.version>Brixton.SR2</spring.cloud.release.version> 
    </properties> 

    <dependencies> 

     <dependency> 
      <groupId>org.springframework.boot</groupId> 
      <artifactId>spring-boot-starter-thymeleaf</artifactId> 
     </dependency> 
     <dependency> 
      <groupId>org.springframework.boot</groupId> 
      <artifactId>spring-boot-starter-actuator</artifactId> 
     </dependency> 
     <dependency> 
      <groupId>org.springframework.boot</groupId> 
      <artifactId>spring-boot-starter-data-jpa</artifactId> 
     </dependency> 
     <dependency> 
      <groupId>org.springframework.boot</groupId> 
      <artifactId>spring-boot-starter-data-rest</artifactId> 
     </dependency> 
     <dependency> 
      <groupId>org.springframework.boot</groupId> 
      <artifactId>spring-boot-starter-web</artifactId> 
     </dependency> 

     <!-- eureka discovery client --> 
     <dependency> 
      <groupId>org.springframework.cloud</groupId> 
      <artifactId>spring-cloud-starter-eureka</artifactId> 
     </dependency> 

     <dependency> 
      <groupId>mysql</groupId> 
      <artifactId>mysql-connector-java</artifactId> 
      <scope>runtime</scope> 
     </dependency> 

     <!-- for unit tests --> 
     <dependency> 
      <groupId>org.springframework.boot</groupId> 
      <artifactId>spring-boot-starter-test</artifactId> 
      <scope>test</scope> 
     </dependency> 

     <!-- for rest documentation --> 
     <dependency> 
      <groupId>org.springframework.restdocs</groupId> 
      <artifactId>spring-restdocs-mockmvc</artifactId> 
      <scope>test</scope> 
     </dependency> 

     <!-- for (un)marshalling of json/xml --> 
     <dependency> 
      <groupId>com.fasterxml.jackson.core</groupId> 
      <artifactId>jackson-databind</artifactId> 
     </dependency> 
     <dependency> 
      <groupId>com.fasterxml.jackson.dataformat</groupId> 
      <artifactId>jackson-dataformat-xml</artifactId> 
     </dependency> 

     <dependency> 
      <!-- jsoup HTML parser library @ http://jsoup.org/ --> 
      <groupId>org.jsoup</groupId> 
      <artifactId>jsoup</artifactId> 
      <version>1.9.2</version> 
     </dependency> 

    </dependencies> 

    <dependencyManagement> 
     <dependencies> 
      <!-- also needed for eureka discovery --> 
      <dependency> 
       <groupId>org.springframework.cloud</groupId> 
       <artifactId>spring-cloud-dependencies</artifactId> 
       <version>${spring.cloud.release.version}</version> 
       <type>pom</type> 
       <scope>import</scope> 
      </dependency> 
     </dependencies> 
    </dependencyManagement> 

    <build> 
     <finalName>${artifactId}</finalName> 
     <plugins> 
      <plugin> 
       <groupId>org.springframework.boot</groupId> 
       <artifactId>spring-boot-maven-plugin</artifactId> 
       <configuration> 
        <executable>true</executable> 
        <outputDirectory>${dir}</outputDirectory> 
       </configuration> 
      </plugin> 
     </plugins> 
    </build> 
</project> 

我使用MYSQL作爲DB的Spring Boot Server。當我負載測試(JMeter的)超過100個線程/用戶,我得到這個異常:

org.apache.tomcat.jdbc.pool.PoolExhaustedException:[HTTP-NIO-8015-EXEC-195 ]超時:池空。無法在60秒內獲取連接,但沒有可用的[size:50;忙:50;空閒:0; lastwait:60000]。

我的數據源配置:

spring.datasource.tomcat.minIdle = 0 
spring.datasource.tomcat.maxIdle = 10 
spring.datasource.tomcat.maxActive = 50 
spring.datasource.tomcat.maxWait = 60000 
spring.datasource.tomcat.testOnBorrow = true 
spring.datasource.tomcat.timeBetweenEvictionRunsMillis = 1800000 // Updated 
spring.datasource.tomcat.numTestsPerEvictionRun = 50 // Updated 
spring.datasource.tomcat.minEvictableIdleTimeMillis = 10 
spring.datasource.tomcat.validationQuery = SELECT 1 
spring.datasource.tomcat.testWhileIdle = true 

上唯一的數據庫查詢是一個簡單的SELECT * FROM TABLE WHERE deletedat IS NULL。它在約0.01秒內返回約4000個條目(通過mysql CLI)。
我已經安裝了Neor Profile SQL來剖析我的MYSQL數據庫。當我檢查所有進程時,我的Schema上的進程都是Sleeping。這看起來像我的配置不釋放這些連接。

我使用從CrudRepository延伸的簡單接口:

public interface MyRepository extends CrudRepository<MyModel, String> { 
    @Query("SELECT m from MyModel m WHERE m.deletedAt IS NULL") 
    List<MyModel> findWhereDeletedAtIsNull(); 
} 

,並用它

List<MyModel> myModelList = myRepository.findWhereDeletedAtIsNull(); 

我缺少什麼?
似乎無論是配置還是代碼需要進行調整才能釋放連接。

Hibernate的配置:

spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect 
+1

你爲timeBetweenEvictionRunsMillis設置和minEvictableIdleTimeMillis太低的值,這是毫秒... Tomcat的文檔說「值不應小於1秒設定」,即1000,甚至似乎經常要運行驗證查詢...看看是否調整這些值有助於... – MattR

+0

可能是你可以添加像tomcat和啓動版本的依賴信息到帖子,也可以增加日誌記錄的春季開機查看是否在日誌中找到任何內容 – Veeram

+0

連接池參數在哪裏? –

回答

3

您的jpa配置註冊OpenEntityManagerInViewInterceptor,它將JPA EntityManager綁定到工作線程,以便處理整個請求。因此,在完成服務方法(com.example.api.UserService.getAllUser())之後,數據庫連接將關閉(或返回到池)。

這會使您的數據庫連接更長時間保持打開狀態,並且連接池在加載期間耗盡。

要解決您的問題,您可以通過在application.properties加入below property

spring.jpa.open,在視圖=假

此屬性禁用OpenEntityManagerInViewInterceptor過濾器的自動登記默認情況下爲true。

請參閱相關的問題:1。 Consider not registering OpenEntityManagerInViewInterceptor by default

+0

得試試這個,但它似乎是問題所在。我確定它現在可以工作後,我會接受你的回答 –

1

什麼是重要的,在這裏,是爲了讓logAbandoned。這樣,Tomcat的JDBC池會告訴你哪裏有連接正在被分配,但沒有被返回。截至目前,您只是試圖通過覆蓋問題來恢復:迫使池釋放未正確返回的連接。

java.sql.SQLException: Connection has already been closed正在發生,因爲您有一個查詢需要超過50秒才能完成,但它正在被自己的代碼正確清理。因此,在50秒後,池關閉連接(因爲它已被「廢棄」),然後當您的代碼獲得控制權時,它還關閉連接。考慮提高您的遺棄連接超時。

+0

從字面上總結了問題非常好。我剛剛添加了一個展示項目。直到線程完成後,似乎連接纔會被釋放。即使我不再使用連接。我怎樣才能手動關閉連接,這是否是一種好的做法? –

+0

對不起...休眠不是我的果醬。我手寫JDBC,就像上帝的意圖一樣。 '@ Transactional'註釋是否擴大了連接的使用範圍?也許該註釋意味着在該請求期間執行的任何查詢都應該組合在一個事務中,這意味着該連接必須是該請求的唯一內容。直到它完成爲止。您可能需要考慮手動編寫一些JDBC代碼。這是更多的工作,但它會更有效率,並做到你想做的事情。 –

+0

https://github.com/bastiankemmer/Spring-Hibernate-Problem 選擇該項目。 '@ Transactional'確定了單個數據庫事務的範圍,但不是我的問題的一部分。 –