在 spring 中,有以下三种方式来创建数据源:
- 通过 jndi 获取应用服务器中的数据源;
- 在 spring 容器中配置数据源;
- 通过代码来创建数据源,这种方式适用于无容器依赖的单元测试。
1 配置数据源
spring 在第三方依赖包中包含了 2 种数据源的实现包 一个是 apache 的 dbcp;另一个是 c3p0。 我们可以在 spring 配置文件中直接配置这些数据源 。
1.1 dbcp
dbcp (database connection pool)是一个依赖 jakarta commons-pool 对象池机制的数据库连接池,所以在类路径下还必须包括 commons-pool.jar。 下面是使用 dbcp 配置 mysql 数据源的配置片段:
1
2
3
4
5
6
|
<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 的异常 。
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 数据源的配置片段:
1
2
3
4
5
6
|
<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 类 。 下面是一个简单的配置:
1
2
|
<bean id= "datasource" class = "org.springframework.jndi.jndiobjectfactorybean"
p:jndiname= "java:comp/env/jdbc/ds" />
|
spring2.0+ 为获取 j2ee 资源提供了一个 jee 命名空间,通过 jee 命名空间,可以有效地简化 j2ee 资源的引用:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
<?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 数据源实现类既可以通过配置直接使用,也可以在代码中实例化调用:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
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();
}
|
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。
原文链接:https://www.jianshu.com/p/d23f1d418fe6