Spring JDBC连接池最佳实践

44

我有一个基本的Spring JDBC应用程序,配置相当基础:

<bean id="myDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
   <property name="driverClassName" value="oracle.jdbc.OracleDriver"/>
   <property name="url" value="jdbc:oracle:thin:@1.1.1.1:1521:XXX"/>
   <property name="username" value="username"/>
   <property name="password" value="password"/>
</bean>

<bean id="dbThing" class="com.DbThing">
   <property name="dataSource" ref="myDataSource"/>
</bean>

我想介绍一个连接池,并在stackoverflow上阅读了几篇文章后,对于使用哪个连接池库感到有些困惑。

在stackoverflow上得到更多赞誉的库是 C3P0DBCP。由于我正在使用Oracle,我也可以使用驱动程序提供的池化数据源

我知道还有更多可用的库 - 例如新的Apache Tomcat 7连接池库。

有什么库应该真正避免使用吗?

针对给定库,是否有任何推荐的配置?

你愿意分享什么“战斗经历”吗?

4个回答

23
C3PO和DBCP的开发已经停滞,主要是因为它们已经很成熟了。我看到这两个驱动程序都能支持每秒数百个事务。
Tomcat池是一个重新设计和更新的DBCP驱动程序。MyBatis 3.0也包含了自己的池实现,基于代码检查,似乎很可靠。最后,有BoneCP声称具有最佳性能。我还没有在项目中使用过其中任何一个。
可能最好的建议是选择其中任何一个进行测试。Spring使其易于稍后更换。

5
BoneCP已经停止维护。你可以尝试使用HikariCP作为一个高效的固定连接池。它具有出色的性能表现。你可以在HikariCP网站上查看更多信息。 - muruga

17

你是否尝试过甲骨文自己的数据库连接池,作为BoneCP的替代方案?我在最近几周中有很好的体验,所以也许值得一试。而且,当与他们自己的数据库配对使用时,甲骨文可能知道如何制作连接池这件事。

<bean id="dataSource" class="oracle.jdbc.pool.OracleConnectionPoolDataSource">
    <property name="URL" value="${jdbc.url}" />
    <property name="user" value="${jdbc.username}" />
    <property name="password" value="${jdbc.password}" />
</bean>

更新: 如果你正在使用(其中之一)最新的 Oracle JDBC 驱动程序(11.2.0.1+),你可能想尝试一下新的通用连接池 Universal Connection Pool。OracleConnectionPoolDataSource 似乎已被正式弃用,推荐使用这个连接池。但是,一些用户报告使用它时出现错误,因此可能还为时过早。我有机会使用 Oracle 最新的 JDBC 驱动程序,所以我将尝试并在这里更新任何信息。

有关此主题的更多信息,请参见 SO 线程:Oracle UCP


10

BoneCP一直声称自己是最好的连接池工具,但现在有一个新工具叫做HiKariCP,它克服了之前工具中存在的许多缺点,您可以通过下面的更改在application-context.xml中对其进行配置。

<bean id="hikariConfig" class="com.zaxxer.hikari.HikariConfig">
  <property name="maximumPoolSize" value="10" />
  <property name="minimumPoolSize" value="2" />
  <property name="dataSourceClassName" 
            value="oracle.jdbc.pool.OracleDataSource" />
  <property name="dataSourceProperties" ref="props" />
  <property name="poolName" value="springHikariCP" />
</bean>

<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource">
      <constructor-arg ref="hikariConfig" />
</bean>

<util:properties id="props" location="classpath:datasource.properties"/>

database.properties文件中,您需要提供以下类似的数据库详细信息

 url=jdbc:oracle:thin:@IP:port:SID/Databasename
 user=usernmae
 password=password

要进行适当的演示,您可以使用此链接


1
谢谢您的回答,这有助于减轻我们 HikariCP 开发人员的负担。 - brettw
欢迎,@brettw 如果对你有帮助的话,可以点赞哦 :) - Bhargav Modi
1
感谢指出HiKaRi!hikariConfig的小更新。不知道如何格式化注释: <bean id="hikariConfig" class="com.zaxxer.hikari.HikariConfig"> <property name="maximumPoolSize" value="50"/> <property name="driverClassName" value="${db.driver}"/> <property name="jdbcUrl" value="${db.url}"/> <property name="username" value="${db.username}"/> <property name="password" value="${db.password}"/> </bean> - Ondrej Burkert

6

您可以使用C3P0,这是专为企业解决方案开发的。要检查其优势,可以查看此答案

以下是集成示例代码:

@Bean
    public JpaTransactionManager transactionManager() {
        JpaTransactionManager transactionManager =
                new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
        return transactionManager;
    }

这个Bean是用于获取JpaTransactionManager

@Primary
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {

    LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
    entityManagerFactoryBean.setDataSource(dataSource());
    entityManagerFactoryBean.setPersistenceProviderClass(HibernatePersistenceProvider.class);
    entityManagerFactoryBean.setPackagesToScan("YOUR.DATABSE.ENTITY.PACKAGE");
    entityManagerFactoryBean.setJpaProperties(hibProperties());

    return entityManagerFactoryBean;
}

这个Bean用于获取LocalContainerEntityManagerFactoryBean。它需要DataSourcePersistenceProviderClass、实体包名PackagesToScanhibProperties()提供的JpaProperties。

@Bean
    public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
        return new PersistenceExceptionTranslationPostProcessor();
    }

private Properties hibProperties() {
        Properties properties = new Properties();
        properties.put("hibernate.dialect", env.getProperty("hibernate.dialect"));
        properties.put("hibernate.show_sql", env.getProperty("hibernate.show_sql"));
        properties.put("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto"));
        return properties;
    }

在这里,env value来自于application.properties文件。
请查看下面的配置属性:
hibernate.dialect: org.hibernate.dialect.Oracle12cDialect
hibernate.show_sql: false
hibernate.hbm2ddl.auto: none

主要部分是数据源设置。以下是给出的内容:

@Bean
    public ComboPooledDataSource dataSource(){
        ComboPooledDataSource dataSource = new ComboPooledDataSource();

        try {
            dataSource.setDriverClass(env.getProperty("db.driver"));
            dataSource.setJdbcUrl(env.getProperty("db.url"));
            dataSource.setUser(env.getProperty("db.username"));
            dataSource.setPassword(env.getProperty("db.password"));
            dataSource.setMinPoolSize(Integer.parseInt(env.getProperty("minPoolSize")));
            dataSource.setMaxPoolSize(Integer.parseInt(env.getProperty("maxPoolSize")));
            dataSource.setMaxIdleTime(Integer.parseInt(env.getProperty("maxIdleTime")));
            dataSource.setMaxStatements(Integer.parseInt(env.getProperty("maxStatements")));
            dataSource.setMaxStatementsPerConnection(Integer.parseInt(env.getProperty("maxStatementsPerConnection")));
            dataSource.setMaxIdleTimeExcessConnections(10000);

        } catch (PropertyVetoException e) {
            e.printStackTrace();
        }
        return dataSource;
    }

它使用的是ComboPooledDataSource,该类有许多重要参数,如maxPoolSize、MinPoolSize、MaxIdleSize等。 以下是它的环境参数:

db.driver: oracle.jdbc.driver.OracleDriver // for Oracle
db.username: YOUR_USER_NAME
db.password: YOUR_USER_PASSWORD
db.url: DATABASE_URL
minPoolSize:5 // number of minimum poolSize
maxPoolSize:100 // number of maximum poolSize
maxIdleTime:5 // In seconds. After that time it will realease the unused connection.
maxStatements:1000
maxStatementsPerConnection:100
maxIdleTimeExcessConnections:10000

以下是完整的可工作示例代码:

import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.hibernate.jpa.HibernatePersistenceProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.*;
import org.springframework.core.env.Environment;
import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.sql.DataSource;
import java.beans.PropertyVetoException;
import java.util.Properties;

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories
@PropertySource("classpath:application.properties")
@Scope("singleton")
public class TestDataSource {

    @Autowired
    private Environment env;

    @Qualifier("dataSource")
    @Autowired
    private DataSource dataSource;

    @Bean
    public JpaTransactionManager transactionManager() {
        JpaTransactionManager transactionManager =
                new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
        return transactionManager;
    }

    @Primary
    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() {

        LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
        entityManagerFactoryBean.setDataSource(dataSource());
        entityManagerFactoryBean.setPersistenceProviderClass(HibernatePersistenceProvider.class);
        entityManagerFactoryBean.setPackagesToScan("YOUR.PACKAGE.NAME");
        entityManagerFactoryBean.setJpaProperties(hibProperties());

        return entityManagerFactoryBean;
    }

    @Bean
    public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
        return new PersistenceExceptionTranslationPostProcessor();
    }

    @Bean
    public ComboPooledDataSource dataSource(){
        ComboPooledDataSource dataSource = new ComboPooledDataSource();

        try {
            dataSource.setDriverClass(env.getProperty("db.driver"));
            dataSource.setJdbcUrl(env.getProperty("db.url"));
            dataSource.setUser(env.getProperty("db.username"));
            dataSource.setPassword(env.getProperty("db.password"));
            dataSource.setMinPoolSize(Integer.parseInt(env.getProperty("minPoolSize")));
            dataSource.setMaxPoolSize(Integer.parseInt(env.getProperty("maxPoolSize")));
            dataSource.setMaxIdleTime(Integer.parseInt(env.getProperty("maxIdleTime")));
            dataSource.setMaxStatements(Integer.parseInt(env.getProperty("maxStatements")));
            dataSource.setMaxStatementsPerConnection(Integer.parseInt(env.getProperty("maxStatementsPerConnection")));
            dataSource.setMaxIdleTimeExcessConnections(10000);

        } catch (PropertyVetoException e) {
            e.printStackTrace();
        }
        return dataSource;
    }

    private Properties hibProperties() {
        Properties properties = new Properties();
        properties.put("hibernate.dialect", env.getProperty("hibernate.dialect"));
        properties.put("hibernate.show_sql", env.getProperty("hibernate.show_sql"));
        properties.put("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto"));
        return properties;
    }
}

还有一些其它的东西。这里是Gradle链接。

compile group: 'org.hibernate', name: 'hibernate-c3p0', version: '5.2.10.Final'

希望这能对您有所帮助。谢谢 :)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接