Java连接池不限制打开到DB服务器的TCP连接数

时间:2016-01-25 06:04:12

标签: java spring hibernate orm connection-pooling

我正在使用Hibernate属性来定义连接池大小,以及LocalSessionFactoryBeanDriverManagerDataSource来创建org.hibernate.SessionFactory,我正在观察1000个TCP连接被打开到数据库服务器而不是我预期的连接池大小的上限。

设置连接Hibernate池的代码如下所示。请注意最大大小为100,但是我正在观察从我的工作站到数据库服务器的1000个连接 - 我在Windows机器上使用TCPView连接到由Vagrant(VirtualBox)管理的Centos OS VM上的MariabDB实例

Properties hibernateProperties = new Properties();
hibernateProperties.put("hibernate.dialect", "org.hibernate.dialect.MySQL5InnoDBDialect");
hibernateProperties.put("hibernate.show_sql", false);
hibernateProperties.put("hibernate.generate_statistics", false);
hibernateProperties.put("hibernate.hbm2ddl.auto", "update");
hibernateProperties.put("hibernate.use_sql_comments", false);

hibernateProperties.put("hibernate.c3p0.min_size", 10);
hibernateProperties.put("hibernate.c3p0.max_size", 100);
hibernateProperties.put("hibernate.c3p0.timeout", 1500);
hibernateProperties.put("hibernate.c3p0.max_statements", 5000);
hibernateProperties.put("hibernate.c3p0.idle_test_period", 60);

LocalSessionFactoryBean localSessionFactoryBean = new   LocalSessionFactoryBean();
localSessionFactoryBean.setDataSource(dataSource);
localSessionFactoryBean.setHibernateProperties(hibernateProperties);
localSessionFactoryBean.setMappingResources("job.persistence.xml");

我希望看到这些连接最大值为100,并在以后执行循环时重复使用,但我观察超过1000次坐在TIME_WAIT中大约一分钟才关闭它们。以下是TCPView输出的示例:

[System Process]    0   TCP localhost   62794   192.168.98.102  3306    TIME_WAIT                                       
[System Process]    0   TCP localhost   62796   192.168.98.102  3306    TIME_WAIT                                       
[System Process]    0   TCP localhost   62797   192.168.98.102  3306    TIME_WAIT                                       
[System Process]    0   TCP localhost   62795   192.168.98.102  3306    TIME_WAIT                                       
[System Process]    0   TCP localhost   62798   192.168.98.102  3306    TIME_WAIT                                       
[System Process]    0   TCP localhost   62801   192.168.98.102  3306    TIME_WAIT   

我显然做错了什么但不确定是什么。我使用Spring来管理提供数据访问逻辑的DAO。 DAO被注册为原型Spring范围,而Singleton SessionFactory被注入到DAO中,如下所示:

@Bean(name="jobDao")
@Scope(SpringBeanScope.Prototype)
public JobDao jobDao(SessionFactory jobSessionFactory) { //...}

在DAO中,我正在调用sessionFactory.getCurrentSession()来访问数据库会话。以下是通用DAO基础的摘录,用于演示:

protected Session currentSession() {
    return sessionFactory.getCurrentSession();
}

@Transactional
@Override
public void Add(TEntity entity) {

    currentSession().save(entity);
}

当连接池限制为100时,有谁知道为什么要打开这么多TCP连接?

更新

由于此问题出现在Windows开发计算机上,因此我将一个小型.NET控制台应用程序放在一起,该应用程序使用并行for循环执行简单的SQL select语句,最大线程数为64,每次都创建一个新连接:

public void Test()
{
    ParallelOptions options = new ParallelOptions();
    options.MaxDegreeOfParallelism = 64;

    Parallel.For(0,
                1000,
                options,
                (i, state) =>
                {
                    ExecuteSql();
                });
}

private void ExecuteSql()
{
    SqlDataAdapter adapter = new SqlDataAdapter(sql, new SqlConnection(connectionString));

    DataSet orders = new DataSet();
    adapter.Fill(orders, "Order");

    Console.WriteLine("Thread {0} returned {1} rows", Thread.CurrentThread.ManagedThreadId, orders.Tables[0].Rows.Count);
}

TCPView结果如下所示,这是我期望在连接池解决方案中看到的,即 TCP连接被重用

DatabaseTcpPortTester.vshost.exe    5036    TCP localhost   61316   dev-database01  ms-sql-s    ESTABLISHED 1   88  776 2,684,495       43,800      16      
DatabaseTcpPortTester.vshost.exe    5036    TCP localhost   61317   dev-database01  ms-sql-s    ESTABLISHED 1   88  507 1,998,709       6,326       1       
DatabaseTcpPortTester.vshost.exe    5036    TCP localhost   61318   dev-database01  ms-sql-s    ESTABLISHED 2   176 862 3,081,722       49,640      19      
DatabaseTcpPortTester.vshost.exe    5036    TCP localhost   61319   dev-database01  ms-sql-s    ESTABLISHED 2   176 952 3,128,657       14,600      9       
DatabaseTcpPortTester.vshost.exe    5036    TCP localhost   61320   dev-database01  ms-sql-s    ESTABLISHED 2   176 1,149   3,569,440       25,747      8       
DatabaseTcpPortTester.vshost.exe    5036    TCP localhost   61321   dev-database01  ms-sql-s    ESTABLISHED 2   176 1,166   3,788,974                       
DatabaseTcpPortTester.vshost.exe    5036    TCP localhost   61322   dev-database01  ms-sql-s    ESTABLISHED 2   176 884 3,197,392       8,713       2       
DatabaseTcpPortTester.vshost.exe    5036    TCP localhost   61323   dev-database01  ms-sql-s    ESTABLISHED 2   176 535 1,816,150                       
DatabaseTcpPortTester.vshost.exe    5036    TCP localhost   61324   dev-database01  ms-sql-s    ESTABLISHED 2   176 631 2,197,973                       
DatabaseTcpPortTester.vshost.exe    5036    TCP localhost   61327   dev-database01  ms-sql-s    ESTABLISHED 2   176 1,037   3,344,226       18,980      5       
DatabaseTcpPortTester.vshost.exe    5036    TCP localhost   61328   dev-database01  ms-sql-s    ESTABLISHED 3   264 1,271   4,057,097       30,660      13      
DatabaseTcpPortTester.vshost.exe    5036    TCP localhost   61331   dev-database01  ms-sql-s    ESTABLISHED 2   176 780 2,639,988       8,760       2       
DatabaseTcpPortTester.vshost.exe    5036    TCP localhost   61333   dev-database01  ms-sql-s    ESTABLISHED 2   176 1,041   3,352,777       31,248      12      
DatabaseTcpPortTester.vshost.exe    5036    TCP localhost   61334   dev-database01  ms-sql-s    ESTABLISHED 6   995 729 2,387,668                       
DatabaseTcpPortTester.vshost.exe    5036    TCP localhost   61335   dev-database01  ms-sql-s    ESTABLISHED 6   995 601 1,917,537       23,937      6       
DatabaseTcpPortTester.vshost.exe    5036    TCP localhost   61336   dev-database01  ms-sql-s    ESTABLISHED                                     
DatabaseTcpPortTester.vshost.exe    5036    TCP localhost   61339   dev-database01  ms-sql-s    ESTABLISHED                                     
DatabaseTcpPortTester.vshost.exe    5036    TCP localhost   61340   dev-database01  ms-sql-s    ESTABLISHED                                     
DatabaseTcpPortTester.vshost.exe    5036    TCP localhost   61342   dev-database01  ms-sql-s    ESTABLISHED                                     
DatabaseTcpPortTester.vshost.exe    5036    TCP localhost   61343   dev-database01  ms-sql-s    ESTABLISHED                                     
DatabaseTcpPortTester.vshost.exe    5036    TCP localhost   61344   dev-database01  ms-sql-s    ESTABLISHED                                     
DatabaseTcpPortTester.vshost.exe    5036    TCP localhost   61345   dev-database01  ms-sql-s    ESTABLISHED                                     
DatabaseTcpPortTester.vshost.exe    5036    TCP localhost   61346   dev-database01  ms-sql-s    ESTABLISHED                                     
DatabaseTcpPortTester.vshost.exe    5036    TCP localhost   61356   dev-database01  ms-sql-s    ESTABLISHED                                     
DatabaseTcpPortTester.vshost.exe    5036    TCP localhost   61357   dev-database01  ms-sql-s    ESTABLISHED                                     
DatabaseTcpPortTester.vshost.exe    5036    TCP localhost   61358   dev-database01  ms-sql-s    ESTABLISHED                                     
DatabaseTcpPortTester.vshost.exe    5036    TCP localhost   61359   dev-database01  ms-sql-s    ESTABLISHED                                                         
DatabaseTcpPortTester.vshost.exe    5036    TCP localhost   61362   dev-database01  ms-sql-s    ESTABLISHED                                     
DatabaseTcpPortTester.vshost.exe    5036    TCP localhost   61363   dev-database01  ms-sql-s    ESTABLISHED                                     
DatabaseTcpPortTester.vshost.exe    5036    TCP localhost   61364   dev-database01  ms-sql-s    ESTABLISHED                                     
DatabaseTcpPortTester.vshost.exe    5036    TCP localhost   61365   dev-database01  ms-sql-s    ESTABLISHED                                     
DatabaseTcpPortTester.vshost.exe    5036    TCP localhost   61369   dev-database01  ms-sql-s    ESTABLISHED                                     
[System Process]    0   TCP localhost   61395   dev-database01  epmap   TIME_WAIT

3 个答案:

答案 0 :(得分:2)

在netstat输出中,所有这些都处于TIME_WAIT状态,指示实际关闭之前TCP套接字的状态。这并不意味着数据库连接处于活动状态,只是TCP正处于套接字关闭的过程中。

其中有多少人处于ESTABLISHED州?这将告诉您在该时间点打开的数据库连接的确切数量。

您可以参考以下链接了解不同的TCP套接字状态。 https://en.wikipedia.org/wiki/Transmission_Control_Protocol

答案 1 :(得分:0)

Hibernate配置正确,您应该使用C3P0。如果您为每个请求创建SessionFactory,那么您可以看到比最大池大小更多的连接的唯一方法。

从你的配置中,我看到DAO被创建为原型,这是不寻常的,因为它们应该是单身。确保LocalSessionFactoryBean也不使用原型范围。

答案 2 :(得分:0)

问题是当使用DriverManagerDataSource并且通过在LocalSessionFactoryBean

上设置c3p0属性让hibernate管理池时,c3p0从未被初始化

所以我切换到ComboPooledDataSource并使用此处提供的setter方法设置c3p0属性,而不是LocalSessionFactoryBean,因此您最终会得到以下结果:

@Bean(name="dataSource")
public DataSource dataSource() throws PropertyVetoException {

    Properties hibernateProperties = new Properties();
    hibernateProperties.put("hibernate.dialect", "org.hibernate.dialect.MySQL5InnoDBDialect");
    hibernateProperties.put("hibernate.show_sql", false);
    hibernateProperties.put("hibernate.generate_statistics", false);
    hibernateProperties.put("hibernate.hbm2ddl.auto", "update");
    hibernateProperties.put("hibernate.use_sql_comments", false);

    //note the "hibernate.c3p0...." properties are no longer in use

    ComboPooledDataSource dataSource = new ComboPooledDataSource();

    dataSource.setDriverClass(jobDatabaseProperties.getJobDatabaseDriverClassName());
    dataSource.setJdbcUrl(jobDatabaseProperties.getJobDatabaseUrl());
    dataSource.setUser(jobDatabaseProperties.getJobDatabaseUsername());
    dataSource.setPassword(jobDatabaseProperties.getJobDatabasePassword());

    dataSource.setAcquireIncrement(1);
    dataSource.setMinPoolSize(5);
    dataSource.setMaxPoolSize(100);
    dataSource.setMaxIdleTime(20);

    return new dataSource;
}

我现在可以看到c3p0在日志中被初始化,并且池中按照预期控制了连接数。

http://syntx.io/configuring-c3p0-connection-pooling-with-spring-and-hibernate/

上提示“ 让Spring管理游戏 ”部分