说说在 Spring 中如何使用数据源(DBCP、C3P0、JNDI 等)

版权声明:如果喜欢,就收藏吧 O(∩_∩)O~ https://blog.csdn.net/deniro_li/article/details/83447863

在 Spring 中,有以下三种方式来创建数据源:

  1. 通过 JNDI 获取应用服务器中的数据源;
  2. 在 Spring 容器中配置数据源;
  3. 通过代码来创建数据源,这种方式适用于无容器依赖的单元测试。

1 配置数据源

Spring 在第三方依赖包中包含了 2 种数据源的实现包 一个是 Apache 的 DBCP;另一个是 C3P0。 我们可以在 Spring 配置文件中直接配置这些数据源 。

1.1 DBCP

DBCP (Database Connection Pool)是一个依赖  Jakarta   commons-pool 对象池机制的数据库连接池,所以在类路径下还必须包括 commons-pool.jar。 下面是使用 DBCP 配置 MySql 数据源的配置片段:

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">        
    <property name="driverClassName" value="com.mysql.jdbc.Driver" />       
    <property name="url" value="jdbc:mysql://localhost:3309/db" />       
    <property name="username" value="root" />       
    <property name="password" value="xxxxxx" />       
</bean>   

BasicDataSource 提供了 close() 方法用于关闭数据源,所以必须设定 destroy-method=”close”, 以便 Spring 容器关闭时,能够正常关闭数据源。

除以上必须的数据源属性外,还有一些常用的属性。

事务属性:

属性 默认值 说明
defaultAutoCommit true 连接默认为 auto-commit 状态。
defaultReadOnly 驱动默认值 连接默认的 read-only 状态 。如果没有设置则 setReadOnly 方法将不会被调用。( 某些驱动不支持只读模式 , 比如:Informix)
defaultTransactionIsolation 驱动默认值 连接默认的 TransactionIsolation 状态。有这些值:NONE、READ_COMMITTED、READ_UNCOMMITTED、REPEATABLE_READ、SERIALIZABLE。

连接数相关属性:

属性 默认值 说明
initialSize 0 初始化连接数:连接池启动时创建的初始化连接数量。
maxActive 8 最大活动连接 : 连接池在同一时间内能够分配的最大活动连接的数量。如果设置为非正数,则表示不限制。
maxIdle 8 最大空闲连接 : 连接池中容许保持空闲状态的最大连接数量 , 超过的空闲连接将被释放 , 如果设置为负数,则表示不限制。
minIdle 0 最小空闲连接 : 连接池中容许保持空闲状态的最小连接数量 , 低于这个数量将创建新的连接 , 如果设置为 0,则表示不创建。
maxWait 无限 最大等待时间 : 当没有可用连接时 , 连接池等待连接被归还的最大时间 ( 单位为毫秒 ) , 超出时间将抛出异常 , 如果设置为 -1,则表示无限等待。

连接监测与维护相关属性:

属性 默认值 说明
validationQuery 配置 SQL 查询语句 , 用于验证从连接池取出的连接是否可用。如果指定 , 则查询必须是一个 SQL SELECT,并且必须返回至少一行记录。MySQL 中是 “select 1”;在 Oracle 中是 “select 1 from dual”。
testOnBorrow true 指明是否从连接池中取出连接之前进行检测 , 如果检测失败 , 则从池中去除连接并尝试取出另一个新的连接。 注意 : 设置为 true 后如果要生效,则 validationQuery 参数必须正确被设置。
testOnReturn false 指明是否在归还到池中前进行检测。 注意 : 与 testOnBorrow 一样,设置为 true 后如果要生效,则 validationQuery 参数必须正确被设置。
testWhileIdle false 指明连接是否会被空闲连接回收器 ( 如果有 ) 所检测。 如果检测失败 , 则连接将从池中被移除。 注意 : 设置为 true 后如果要生效,则 validationQuery 参数必须正确被设置。
timeBetweenEvictionRunsMillis -1 空闲连接回收器线程运行的周期 , 以毫秒为单位。如果设置为非正数 , 则不运行空闲连接回收器线程。 注意 : 启用该参数时,则 validationQuery 参数必须正确被设置。
numTestsPerEvictionRun 3 在每次空闲连接回收器线程 ( 如果有 ) 运行时需要检测的连接数量。
minEvictableIdleTimeMillis 1000 * 60 * 30 连接在池中保持空闲而不被空闲连接回收器线程回收的最小时间值,以毫秒为单位。

缓存相关属性:

属性 默认值 说明
poolPreparedStatements false 开启连接池的 prepared statement 功能设置为 true 后,所有的 CallableStatement 和 PreparedStatement 都会被缓存起来。
maxOpenPreparedStatements 不限制 能够同时分配打开的 statements 的最大数量。0 表示不限制。

连接泄露回收相关属性:

属性 默认值 说明
removeAbandoned false 是否删除泄露的连接。如果设置为 true, 那么那些可能存在泄露的连接会被删除。假设 maxActive 为 10 个,活动连接为 8 个,空闲连接为 1 个,10-8-1=1,那么就会把删除这个连接(会先检测该活动连接未被使用的时间是否超过 removeAbandonedTimeout)。如果需要一个长连接操作,那么 removeAbandoned 需要设置的长一些,否则正常使用的连接可能会被误删除。
removeAbandonedTimeout 300 泄露的连接可以被删除的时间段,单位为秒。
logAbandoned false 当 Statement 或连接被泄露时是否打印堆栈日志 。

假设数据库用的是 MySQL,那么如果数据源配置不当,将可能会发生经典的 “8 小时问题 ”。 原因是 MySQL 在默认情况下如果发现一个连接的空闲时间超过 8 小时,那么会在数据库端自动关闭这个连接 。 而数据源并不知道这个连接已经被关闭了,所以当它将这个无用的连接返回给某个 DAO 时, DAO 就会抛出无法获取 connection 的异常 。

扫描二维码关注公众号,回复: 3784678 查看本文章

DBCP 的 testOnBorrow 默认设置为 true,所以从连接池中取出连接之前会先进行检测,因为不会发生 “8 小时问题 ”。 但如果每次取连接时都进行检测,那么在高并发应用下就会产生性能问题。

因此建议在高并发下,将 testOnBorrow 设置为 false;然后将 testWhileIdle 设置为 true,打开空闲连接回收器;最后把 timeBetweenEvictionRunsMillis 的值设定为小于 8 小时,这样那些被 MySQL 所关闭的空闲连接,就会被清除出去。这样不仅解决了 “8 小时问题 ”,而且还保证了高性能 O(∩_∩)O哈哈~

**注意:**因为 MySQL 本身的 interactive-timeout(单位为 s)参数,可以设定空闲连接的过期时间,所以我们要想获取到这个参数值,然后再设定 DBCP 的 timeBetweenEvictionRunsMillis 属性值。

1.2 C3P0

C3P0 是一个开放源代码的 JDBC 数据源实现项目,它实现了 JDBC3 和 JDBC2 扩展规范说明的 Connection 和 Statement 池 。

下面是使用 C3P0 配置 MySql 数据源的配置片段:

<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">        
    <property name="driverClass" value="oracle.jdbc.driver.OracleDriver" />       
    <property name="jdbcUrl" value="jdbc:mysql://localhost:3309/db" />       
    <property name="use" value="xxx" />       
    <property name="password" value="xxxxxx" />       
</bean>   

C3P0 也提供了一个用于关闭数据源的 close() 方法,这样我们就可以保证 Spring 容器被关闭时,能够成功关闭数据源 。

属性 默认值 说明
acquireIncrement 当连接池中无空闲连接时, 一次性创建新连接的数量。
acquireRetryAttempts 30 在从数据库获取新连接失败后,重复尝试的次数。
acquireRetryDelay 1000 尝试获取连接之间的间隔时间,单位为毫秒。
autoCommitOnClose false 连接关闭时,将所有未提交的操作回滚 。
automaticTestTable null 会创建一张名为 Test 的空表,并使用其自带的查询语句进行测试 。 如果定义了这个参数,那么 preferredTestQuery 属性 将被忽略 。 我们不能在这张 Test 表上进行任何操作,它仅为 C3P0 测试所用。
breakAfterAcquireFailure false 获取连接失败时,将会引起所有等待获取连接的线程抛出异常 。 但是数据源仍有效保留,并在下次调用 getConnection() 时继续尝试获取连接 。 在尝试获取连接失败后,该数据源将申明已断开并永久关闭。
checkoutTimeout 0 当连接池中的连接用完时,客户端调用 getConnection() 后等待获取新连接的时间,单位:毫秒。超时后将抛出 SQLException 。设为 0 表示无限期等待 。
connectionTesterClassName com.mchange.v2.C3P0.impl.DefaultConnectionTester 通过实现 ConnectionTester 或 QueryConnectionTester 的类来测试连接,类名需设置为全限定名 。
idleConnectionTestPeriod 0 隔多少秒,检查连接池中的所有空闲连接。0 表示不检查。
initialPoolSize 3 初始化时创建的连接数,应在 minPoolSize 与 maxPoolSize 之间取值 。
maxIdleTime 0 最大空闲时间,超过空闲时间的连接将会被丢弃 。 为 0 或负数则表示永不丢弃 。
maxPoolSize 15 连接池中保留的最大连接数 。
maxStatements 0 JDBC 标准参数,用以控制数据源内加载的 PreparedStatement 数量 。 但由于预缓存的 Statement 属于单个 Connection 而不是整个连接池 。 所以设置这个参数需要多方面的考虑,如果 maxStatements 与 maxStatementsPerConnection 均为 0 ,则缓存被关闭 。
maxStatementsPerConnection 0 连接池内单个连接所拥有的最大缓存 Statement 数 。
numHelperThreads 3 C3P0 是异步操作的,缓慢的 JDBC 操作通过 HelperThreads 完成 。 通过多线程实现多个操作同时被执行,这样可以有效地提升性能。
preferredTestQuery null 定义所有连接测试都执行的测试语句。在使用连接测试的情况下,这个参数能够显著地提高测试速度。测试的表必须在初始数据源时就存在。
propertyCycle 300 修改系统配置参数生效时长,单位为 s。
testConnectionOnCheckout false 因性能消耗大,所以请只在需要时开启 。 如果设为 true 那么在每个 connection 提交的时候都将校验其有效性 。 建议使用 idleConnectionTestPeriod 或 automaticTestTable 等方法来提升连接测试的性能 。
testConnectionOnCheckin false 如果设为 true,那么在取得连接的同时将校验其连接的有效性。

2 JNDI 数据源

如果应用配置在高性能的应用服务器(如 WebLogic 或 Websphere 等)上,我们可能更希望使用应用服务器所提供的数据源 。 应用服务器的数据源使用 JNDI 方式来供调用者使用, Spring 为此专门提供了引用 JNDI 资源的 JndiObjectFactoryBean 类 。 下面是一个简单的配置:

<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean"
	  p:jndiName="java:comp/env/jdbc/ds"/>

Spring2.0+ 为获取 J2EE 资源提供了一个 jee 命名空间,通过 jee 命名空间,可以有效地简化 J2EE 资源的引用:

<?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:p="http://www.springframework.org/schema/p"
       xmlns:jee="http://www.springframework.org/schema/jee"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
      http://www.springframework.org/schema/jee
      http://www.springframework.org/schema/jee/spring-jee-4.0.xsd
      ">

    <jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/ds"/>

</beans>

3 Spring 数据源实现类

Spring 本身也提供了一个简单的数据源实现类 DriverManagerDataSource ,它位于 org.springframework.jdbc.datasource 包中 。 这个类实现了 javax.sql.DataSource 接口,但它并没有提供池化连接机制,每次调用 getConnection() 方法获取新连接时,只是简单地创建一个新的连接 。它不需要额外的依赖类,所以,这个数据源类比较适合在单元测试中使用 。

Spring 数据源实现类既可以通过配置直接使用,也可以在代码中实例化调用:

DriverManagerDataSource dataSource=new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://127.0.0.1:3306/spring4");
dataSource.setUsername("root");
dataSource.setPassword("");

try {
	Connection connection=dataSource.getConnection();
	if(connection.isClosed()){
		System.out.println("连接已关闭");
	}else{
		System.out.println("连接已开启");
	}
} catch (SQLException e) {
	e.printStackTrace();
}

猜你喜欢

转载自blog.csdn.net/deniro_li/article/details/83447863