【问题标题】:How to Improve Performance of Legacy Spring App: MySQL MySQLNonTransientConnectionException如何提高旧版 Spring 应用程序的性能:MySQL MySQLNonTransientConnectionException
【发布时间】:2018-02-11 18:07:16
【问题描述】:

一直在处理一个基于战争的应用程序,它基本上是一个遗留的 RESTful API 包括:

  • Java 1.7
  • Spring 4.0.3.RELEASE
  • 雄猫 7
  • MySQL 5

我们使用的是 Spring JDBC,而不是通过 try / catch / finally 语句关闭任何连接。

我们的数据源配置文件如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="
 http://www.springframework.org/schema/beans
 http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
 http://www.springframework.org/schema/context
 http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    <bean id="propertyPlaceholder"
        class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="ignoreResourceNotFound" value="true" />
        <property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
        <property name="location" value="file:/opt/db/database.properties"></property>
    </bean>

    <!-- Initialization for data source dbcp -->
    <bean id="dataSourceStore" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName"><value>${db.driver}</value></property>
        <property name="url"><value>${db.mydb.url}</value></property>
        <property name="username"><value>${db.username}</value></property>
        <property name="password"><value>${db.password}</value></property>
        <property name="maxIdle" value="10" />
        <property name="maxActive" value="50" />
        <property name="maxWait" value="100" />
        <property name="defaultAutoCommit" value="false" />
        <property name="removeAbandoned" value="true" />
        <property name="removeAbandonedTimeout" value="1" />
        <property name="minIdle" value="0"></property>
        <property name="timeBetweenEvictionRunsMillis" value="1000"></property>
        <property name="minEvictableIdleTimeMillis" value="1000"></property>
    </bean>
</beans>

我们像这样导入我们的配置:

@Repository
public class StoreDAO {
    String errorCode = "";

    private JdbcTemplate jdbcTemplate;

    @Autowired
    public StoreDAO(@Qualifier("dataSourceStore") DataSource dataSource) {
        this.jdbcTemplate = new JdbcTemplate(dataSource);
    }

    // methods which use Spring JDBC calls (such as SQL Select Statements)
}

当在集群的生产 tomcat7 服务器上运行它时,我们会遇到以下异常(在四个不同的 DAO 中到处都是):

DAO::org.springframework.jdbc.CannotGetJdbcConnectionException: 
Could not get JDBC Connection; nested exception is
com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException:

Data source rejected establishment of connection,  
message from server: "Too many connections"

问题:

  1. 如何将现有代码(导入本地 Spring XML 数据源文件)更改为可以实现 JDBC 连接池的方式?

  2. 是否应该在每次成功的 SQL Select 调用后关闭 try/catch/finally 子句中的 ResultStatement?

例如

finally {
   if (stat != null) stat.close(); 
   if (conn != null)  conn.close(); 
}
  1. 我是否还应该通过编辑 my.cnf 文件来增加 MySQL 数据库中的最大连接数(增加最大连接数会有什么影响?):

    https://dev.mysql.com/doc/refman/5.5/en/server-system-variables.html#sysvar_max_connections

  2. 在 Spring datasource.xml 文件中,我可以简单地增加以下属性中的值吗?

如果有人能提供一些指导,我将不胜感激,因为这是一个遗留应用程序,由于与 MySQL 数据库的“连接太多”而遇到严重的性能问题。

【问题讨论】:

    标签: java mysql spring jdbc


    【解决方案1】:

    如何将现有代码(导入本地 Spring XML 数据源文件)更改为可以实现 JDBC 连接池的方式?

    已经在使用连接池。Apache DBCP(数据库连接池)是一个连接池。

    我是否应该在每次成功的 SQL Select 调用后关闭 try/catch/finally 子句中的 ResultStatement?

    这就是 JdbcTemplate 的全部意义所在。您没有展示任何使用它的 JDBC 代码,但是这个类的全部意义正是为您处理 JDBC 资源的关闭。因此,除非您以非常奇怪的方式使用它,否则资源将被关闭。

    我是否还应该通过编辑 my.cnf 文件来增加 MySQL 数据库中的最大连接数(增加最大连接数会有什么影响?)

    我们无法回答这个问题,因为我们不知道当前数量是多少,您的应用程序有多少实例正在使用数据库,以及您可能需要多少额外的连接(此应用程序未使用,但对于其他应用程序或管理目的是必需的)。您的连接池最多可以打开 50 个到该数据库的活动连接,因此您应该在数据库中允许至少 50 个连接,假设您有一个应用程序实例,并且它是唯一打开到该数据库的连接的东西。

    在 Spring datasource.xml 文件中,我可以简单地增加以下属性中的值吗?

    考虑到你得到的异常(但你没有发布它的堆栈跟踪,所以很难确切知道发生了什么),这只会让事情变得更糟:数据库已经拒绝打开连接,这会告诉池尝试打开更多。如果有的话,您应该减少最大活动连接数。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-08-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多