java - Spring 数据库负载测试 : How to release connections

标签 java mysql spring tomcat

我只是想在一个小案例应用程序中简化我的问题。
似乎在 Thread 完成之前 Connection 不会关闭。 Check this out

依赖信息:

Servlet 引擎:Apache Tomcat/8.5.5
JPA 提供程序:Hibernate

我的 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 作为数据库的 Spring Boot 服务器。当我对超过 100 个线程/用户进行负载测试 (JMeter) 时,出现此异常:

org.apache.tomcat.jdbc.pool.PoolExhaustedException: [http-nio-8015-exec-195] Timeout: Pool empty. Unable to fetch a connection in 60 seconds, none available[size:50; busy:50; idle: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 上的进程都在 hibernate 。似乎我的配置没有释放那些连接。

我正在使用一个从 CrudRepository 扩展而来的简单接口(interface):

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();

我错过了什么?
似乎需要修改 Configuration 或 Code 才能释放连接。

hibernate 配置:

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

最佳答案

注册 OpenEntityManagerInViewInterceptor 的 jpa 配置将 JPA EntityManager 绑定(bind)到工作线程以进行整个请求处理。因此,在服务方法 (com.example.api.UserService.getAllUser()) 完成后,数据库连接将关闭(或返回到池中)。

这会使您的数据库连接打开更长时间,并且您的连接池会在加载期间耗尽。

要解决您的问题,您可以通过添加 below property 来禁用 OpenEntityManagerInViewInterceptor 过滤器的自动注册在你的 application.properties

spring.jpa.open-in-view=false

此属性默认为真。

查看相关问题: 1. Consider not registering OpenEntityManagerInViewInterceptor by default

关于java - Spring 数据库负载测试 : How to release connections,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41218851/

相关文章:

spring - 在 Kotlin Flow 中使用 ReactiveSecurityContextHolder

java - 集换式卡牌游戏中卡牌效果的基本逻辑/流程

mysql - neo4j 示例 - 图与关系概念

java - 在专业 java 应用程序中哪个是首选 jSTL 中的 SQL 或仅在 servlet 中

java - 该步骤不允许使用“skippable-exception-classes”

java - @RequestParam Spring 4.0 -> 4.2

java - 如何将数组中的字符串与字符串进行比较?

Java ArrayList - 无法读回对象的属性

java - 什么是NullPointerException,我该如何解决?

php - 如何通过 MYSQL/PHP 将 .sql.gz 文件导入我的数据库? (不是命令行)