public class DBUtil { /** * 单例模式创建数据库对象 */ private static DBUtil instance=null; private DBUtil(){} //为了保证单例性,必须使用同步关键字 public synchronized static DBUtil getInstance(){ if(instance==null) instance=new DBUtil(); return instance; } //连接必要的信息 public String driver="com.mysql.jdbc.Driver"; public String url="jdbc:mysql://localhost:3306/test"; public String username="root"; public String password="8921498YW"; public Connection getConnection(){ Connection conn=null; try { Class.forName(driver); conn=DriverManager.getConnection(url, username, password); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } return conn; } //测试连接的效率 public static void main(String[] args) throws SQLException { long begin=System.currentTimeMillis();//开始时刻 for(int i=0;i<1000;i++){//获得1000次连接 Connection conn=DBUtil.getInstance().getConnection(); conn.close(); } long end=System.currentTimeMillis(); System.out.println("直接连接数据库所需要的时 间:"+(end-begin)); //在我的机子上1000次直接连接耗时:12031 } }2, 使用 DBCP 连接池: , 连接池: /** * 数据库连接池 : * 它是程序启动时建立足够的数据库连接,并将这些连接组成一个连 接池,由程序动态的对池中的连接进行申请,使用,释放 * * DBCP是apache组织下的一个开源项目 * 需要两个jar包,commons-dbcp-1.2.2和commons-pool * 这种连接池效率很高,但经常出现连接丢失现象,用的不是很多, 用的多的是c3p0 * */
public class DBUtilOfDBCP { private static BasicDataSource dataSource=null;// 数据源 private static DataSourceConnectionFactory factory;//连接工厂 private static DBUtilOfDBCP instance=null; private DBUtilOfDBCP(){ dataSource=new BasicDataSource(); //设置jdbc相关信息 dataSource.setUrl(url); dataSource.setUsername(username); dataSource.setPassword(password); dataSource.setDriverClassName(driver); //连接池设置 dataSource.setInitialSize(20);//初始连接数 dataSource.setMaxActive(100);//最大获取连接数 dataSource.setMaxIdle(30);//最大可用空闲连接数 dataSource.setMinIdle(10);//最小可用空闲连接数 factory=new DataSourceConnectionFactory(dataSource); } //为了保证单例性,必须使用同步关键字 public synchronized static DBUtilOfDBCP getInstance(){ if(instance==null) instance=new DBUtilOfDBCP(); return instance; } //连接必要的信息 public String driver="com.mysql.jdbc.Driver"; public String url="jdbc:mysql://localhost:3306/test"; public String username="root"; public String password="8921498YW"; public Connection getConnection() throws SQLException{ //使用工厂创建连接 return factory.createConnection(); } public static void main(String[] args) throws SQLException { long begin=System.currentTimeMillis();//开始时刻 for(int i=0;i<1000;i++){//获得1000次连接 Connection conn=DBUtilOfDBCP.getInstance().getConnection(); conn.close(); } long end=System.currentTimeMillis(); System.out.println("DBCP连接数据库所需要的时 间:"+(end-begin)); //在我的机子上1000次DBCP连接耗时:1000毫秒 } }3,使用 C3P0 连接池: , 连接池: * C3P0,比较稳定 * 需要jar包:c3p0-0.9.1
public class DBUtilOfC3P0 { private static ComboPooledDataSource dataSource; private static DBUtilOfC3P0 instance=null; private DBUtilOfC3P0(){ dataSource=new ComboPooledDataSource(); //设置jdbc连接信息 dataSource.setUser(username); dataSource.setPassword(password); dataSource.setJdbcUrl(url); try { dataSource.setDriverClass(driver); } catch (PropertyVetoException e) { e.printStackTrace(); } //设置连接池 dataSource.setInitialPoolSize(30); dataSource.setMaxPoolSize(100); dataSource.setMinPoolSize(10); } //为了保证单例性,必须使用同步关键字 public synchronized static DBUtilOfC3P0 getInstance(){ if(instance==null) instance=new DBUtilOfC3P0(); return instance; } //连接必要的信息 public String driver="com.mysql.jdbc.Driver"; public String url="jdbc:mysql://localhost:3306/test"; public String username="root"; public String password="8921498YW"; public Connection getConnection() throws SQLException{ //使用工厂创建连接 return dataSource.getConnection(); } public static void main(String[] args) throws SQLException { long begin=System.currentTimeMillis(); //开始时刻 for(int i=0;i<1000;i++){//获得1000次连接 Connection conn=DBUtilOfC3P0.getInstance().getConnection(); conn.close(); } long end=System.currentTimeMillis(); System.out.println("C3P0连接数据库所需要的时 间:"+(end-begin)); //在我的机子上1000次C3P0连接耗时:1813毫秒 } }
C3PO数据库连接池
优点:性能比较dbcp好,稳定性也比dbcp强
将C3po跟spring整合
1.导入c3p0-0.9.1.2.jar,commons-logging-1.1.1.jar,spring-2.5.6.jar
2.在applicationContext.xml中配置,用C3PO配置好的数据源
<bean
id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass">
<value>net.sourceforge.jtds.jdbc.Driver</value>
</property>
<property name="jdbcUrl">
<value>jdbc:jtds:sqlserver://localhost:1433/hua</value>
</property>
<property name="user">
<value>sa</value>
</property>
<property name="password">
<value>hua</value>
</property>
<property name="minPoolSize">
<value>15</value>
</property>
<property name="acquireIncrement">
<value>5</value>
</property>
<property name="maxPoolSize">
<value>25</value>
</property>
</bean>
3.在dao类中就可以通过
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
DataSource ds=(DataSource)context.getBean("dataSource");
Connection conn=ds.getConnection();
Statement stmt=conn.creatStatement();
ResultSet rs=stmt.executeQuery(sql);
接着介绍一下C3PO的参数
<!--当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。Default: 3 -->
<property name="acquireIncrement">3</property>
<!--定义在从数据库获取新连接失败后重复尝试的次数。Default: 30 -->
<property name="acquireRetryAttempts">30</property>
<!--两次连接中间隔时间,单位毫秒。Default: 1000 -->
<property name="acquireRetryDelay">1000</property>
<!--连接关闭时默认将所有未提交的操作回滚。Default: false -->
<property name="autoCommitOnClose">false</property>
<!--c3p0将建一张名为Test的空表,并使用其自带的查询语句进行测试。如果定义了这个参数那么
属性preferredTestQuery将被忽略。你不能在这张Test表上进行任何操作,它将只供c3p0测试
使用。Default: null-->
<property name="automaticTestTable">Test</property>
<!--获取连接失败将会引起所有等待连接池来获取连接的线程抛出异常。但是数据源仍有效
保留,并在下次调用getConnection()的时候继续尝试获取连接。如果设为true,那么在尝试
获取连接失败后该数据源将申明已断开并永久关闭。Default: false-->
<property name="breakAfterAcquireFailure">false</property>
<!--当连接池用完时客户端调用getConnection()后等待获取新连接的时间,超时后将抛出
SQLException,如设为0则无限期等待。单位毫秒。Default: 0 -->
<property name="checkoutTimeout">100</property>
<!--通过实现ConnectionTester或QueryConnectionTester的类来测试连接。类名需制定全路径。
Default: com.mchange.v2.c3p0.impl.DefaultConnectionTester-->
<property name="connectionTesterClassName"></property>
<!--指定c3p0 libraries的路径,如果(通常都是这样)在本地即可获得那么无需设置,默认null即可
Default: null-->
<property name="factoryClassLocation">null</property>
<!--Strongly disrecommended. Setting this to true may lead to subtle and bizarre bugs.
(文档原文)作者强烈建议不使用的一个属性-->
<property name="forceIgnoreUnresolvedTransactions">false</property>
<!--每60秒检查所有连接池中的空闲连接。Default: 0 -->
<property name="idleConnectionTestPeriod">60</property>
<!--初始化时获取三个连接,取值应在minPoolSize与maxPoolSize之间。Default: 3 -->
<property name="initialPoolSize">3</property>
<!--最大空闲时间,60秒内未使用则连接被丢弃。若为0则永不丢弃。Default: 0 -->
<property name="maxIdleTime">60</property>
<!--连接池中保留的最大连接数。Default: 15 -->
<property name="maxPoolSize">15</property>
<!--JDBC的标准参数,用以控制数据源内加载的PreparedStatements数量。但由于预缓存的statements
属于单个connection而不是整个连接池。所以设置这个参数需要考虑到多方面的因素。
如果maxStatements与maxStatementsPerConnection均为0,则缓存被关闭。Default: 0-->
<property name="maxStatements">100</property>
<!--maxStatementsPerConnection定义了连接池内单个连接所拥有的最大缓存statements数。Default: 0 -->
<property name="maxStatementsPerConnection"></property>
<!--c3p0是异步操作的,缓慢的JDBC操作通过帮助进程完成。扩展这些操作可以有效的提升性能
通过多线程实现多个操作同时被执行。Default: 3-->
<property name="numHelperThreads">3</property>
<!--当用户调用getConnection()时使root用户成为去获取连接的用户。主要用于连接池连接非c3p0
的数据源时。Default: null-->
<property name="overrideDefaultUser">root</property>
<!--与overrideDefaultUser参数对应使用的一个参数。Default: null-->
<property name="overrideDefaultPassword">password</property>
<!--密码。Default: null-->
<property name="password"></property>
<!--定义所有连接测试都执行的测试语句。在使用连接测试的情况下这个一显著提高测试速度。注意:
测试的表必须在初始数据源的时候就存在。Default: null-->
<property name="preferredTestQuery">select id from test where id=1</property>
<!--用户修改系统配置参数执行前最多等待300秒。Default: 300 -->
<property name="propertyCycle">300</property>
<!--因性能消耗大请只在需要的时候使用它。如果设为true那么在每个connection提交的
时候都将校验其有效性。建议使用idleConnectionTestPeriod或automaticTestTable
等方法来提升连接测试的性能。Default: false -->
<property name="testConnectionOnCheckout">false</property>
<!--如果设为true那么在取得连接的同时将校验连接的有效性。Default: false -->
<property name="testConnectionOnCheckin">true</property>
<!--用户名。Default: null-->
<property name="user">root</property>
<!--早期的c3p0版本对JDBC接口采用动态反射代理。在早期版本用途广泛的情况下这个参数
允许用户恢复到动态反射代理以解决不稳定的故障。最新的非反射代理更快并且已经开始
广泛的被使用,所以这个参数未必有用。现在原先的动态反射与新的非反射代理同时受到
支持,但今后可能的版本可能不支持动态反射代理。Default: false-->
DBCP数据连接池
1.导入commons-dbcp.jar,commons-logging-1.1.1.jar,commons-pool.jar,spring-2.5.6.jar
2.在applicationContext.xml中配置数据源
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName"> <value>com.mysql.jdbc.Driver</value>
</property>
<property name="url"> <value>jdbc:mysql://localhost:3306/dbname?useUnicode=true&characterEncoding=utf8</value>
</property>
<property name="username"> <value>root</value> </property>
<property name="password"> <value>root</value> </property>
<property name="initialSize"> <value>3</value> </property>
<property name="maxActive"> <value>100</value> </property>
<property name="maxIdle"> <value>5</value> </property>
<property name="maxWait"> <value>10</value> </property>
</bean>
3.跟上面一样获取数据源
4.参数介绍
Ø BasicDataSource 相关的参数说明
dataSource: 要连接的 datasource (通常我们不会定义在 server.xml)
defaultAutoCommit: 对于事务是否 autoCommit, 默认值为 true
defaultReadOnly: 对于数据库是否只能读取, 默认值为 false
driverClassName:连接数据库所用的 JDBC Driver Class,
maxActive: 可以从对象池中取出的对象最大个数,为0则表示没有限制,默认为8
maxIdle: 最大等待连接中的数量,设 0 为没有限制 (对象池中对象最大个数)
minIdle:对象池中对象最小个数
maxWait: 最大等待秒数, 单位为 ms, 超过时间会丟出错误信息
password: 登陆数据库所用的密码
url: 连接数据库的 URL
username: 登陆数据库所用的帐号
validationQuery: 验证连接是否成功, SQL SELECT 指令至少要返回一行
removeAbandoned: 是否自我中断, 默认是 false
removeAbandonedTimeout: 几秒后会自我中断, removeAbandoned 必须为 true
logAbandoned: 是否记录中断事件, 默认为 false
minEvictableIdleTimeMillis:大于0 ,进行连接空闲时间判断,或为0,对空闲的连接不进行验证;默认30分钟
timeBetweenEvictionRunsMillis:失效检查线程运行时间间隔,如果小于等于0,不会启动检查线程,默认-1
testOnBorrow:取得对象时是否进行验证,检查对象是否有效,默认为false
testOnReturn:返回对象时是否进行验证,检查对象是否有效,默认为false
testWhileIdle:空闲时是否进行验证,检查对象是否有效,默认为false
Ø 在使用DBCP的时候,如果使用默认值,则数据库连接因为某种原因断掉后,再从连接池中取得连接又不进行验证,这时取得的连接实际上就会是无效的数据库连接。因此为了防止获得的数据库连接失效,在使用的时候最好保证:
username: 登陆数据库所用的帐号
validationQuery:SELECT COUNT(*) FROM DUAL
testOnBorrow、testOnReturn、testWhileIdle:最好都设为true
minEvictableIdleTimeMillis:大于0 ,进行连接空闲时间判断,或为0,对空闲的连接不进行验证
timeBetweenEvictionRunsMillis:失效检查线程运行时间间隔,如果小于等于0,不会启动检查线程
Ø PS:在构造GenericObjectPool [BasicDataSource在其createDataSource () 方法中也会使用GenericObjectPool] 时,会生成一个内嵌类Evictor,实现自Runnable接口。如果timeBetweenEvictionRunsMillis大于0,每过timeBetweenEvictionRunsMillis毫秒Evictor会调用evict()方法,检查对象的闲置时间是否大于 minEvictableIdleTimeMillis毫秒(_minEvictableIdleTimeMillis小于等于0时则忽略,默认为30分钟),是则销毁此对象,否则就激活并校验对象,然后调用ensureMinIdle方法检查确保池中对象个数不小于_minIdle。在调用returnObject方法把对象放回对象池,首先检查该对象是否有效,然后调用PoolableObjectFactory 的passivateObject方法使对象处于非活动状态。再检查对象池中对象个数是否小于maxIdle,是则可以把此对象放回对象池,否则销毁此对象
上面两个是基于Apache的开源连接池框架,如果你用的服务器也是Apache的,如:tomcat。建议使用
bonecp数据连接池
1.导入bonecp-0.7.0.jar,commons-logging-1.1.1.jar,google-collections-1.0.jar,log4j-1.2.15.jar,slf4j-api-1.6.0.jar,slf4j-log4j12-1.6.0.jar,spring-2.5.6.jar
2.在applicationContext.xml中配置数据源
<bean id="mainDataSource" class="com.jolbox.bonecp.BoneCPDataSource" destroy-method="close">
<property name="driverClass" value="com.mysql.jdbc.Driver" />
<property name="jdbcUrl" value="jdbc:mysql://127.0.0.1/yourdb" />
<property name="username" value="root"/>
<property name="password" value="abcdefgh"/>
<property name="idleConnectionTestPeriod" value="60"/>
<property name="idleMaxAge" value="240"/>
<property name="maxConnectionsPerPartition" value="30"/>
<property name="minConnectionsPerPartition" value="10"/>
<property name="partitionCount" value="3"/>
<property name="acquireIncrement" value="5"/>
<property name="statementsCacheSize" value="100"/>
<property name="releaseHelperThreads" value="3"/>
</bean>
3.跟上面一样获取数据源
4.
BoneCP最大的特点就是效率,BoneCP号称是目前市面上最快的Java连接池,从官方的评测来看其效率远远超越了其它同类的Java连 接池产品
Proxool数据连接池
1.导入commons-logging.jar,proxool-0.9.0RC3.jar,spring-2.5.6.jar
2.在Spring的"applicationContext.xml"中的dataSource bean定义——
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName">
<value>org.logicalcobwebs.proxool.ProxoolDriver</value>
</property>
<property name="url">
<value>proxool.Pool_dbname</value>
</property>
</bean>
3.在"web.xml"先配置好Proxool连接池
<servlet>
<servlet-name>proxoolServletConfigurator</servlet-name>
<servlet-class>
org.logicalcobwebs.proxool.configuration.ServletConfigurator
</servlet-class>
<init-param>
<param-name>xmlFile</param-name>
<param-value>WEB-INF/proxool.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
4.写一个proxool.xml
<?xml version="1.0" encoding="UTF-8"?>
<proxool-config>
<proxool>
<alias>Pool_dbname</alias>
<driver-url>jdbc:mysql://localhost:3306/dbname</driver-url>
<driver-class>com.mysql.jdbc.Driver</driver-class>
<driver-properties>
<property name="user" value="yourname"/>
<property name="password" value="yourpass"/>
</driver-properties>
<house-keeping-sleep-time>60000</house-keeping-sleep-time>
<maximum-connection-count>20</maximum-connection-count>
<minimum-connection-count>2</minimum-connection-count>
<prototype-count>0</prototype-count>
<simultaneous-build-throttle>20</simultaneous-build-throttle>
<house-keeping-test-sql>select CURRENT_DATE</house-keeping-test-sql>
<statistics>15s,10m,1d</statistics>
<statistics-log-level>INFO</statistics-log-level>
</proxool>
<proxool>
<!--可以配置多个库-->
</proxool>
</proxool-config>
5.最后跟上面一获取数据源
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
DataSource ds=(DataSource)context.getBean("dataSource");
Connection conn=ds.getConnection();
Statement stmt=conn.creatStatement();
ResultSet rs=stmt.executeQuery(sql);
6.参数介绍
#alias是别名;
#driver-url是驱动的url,就是连接的url;
#driver-class是驱动的类,就是数据库驱动;
#user和password是设置登陆数据库的用户名和密码
#prototype-count 最少保持的空闲连接数
#maximum-connection-lifetime 最大连接生命周期 默认值:4小时
#maximum-active-time: 最大活动时间 默认值:5分钟
#maximum-connection-count 最大连接数 默认值:15个
#minimum-connection-count 最小连接数 默认值:5个
#house-keeping-sleep-time proxool自动侦察各个连接状态的时间间隔(毫秒),侦察到空闲的连接就马上回收,超时的销毁
#maximum-new-connections 指因未有空闲连接可以分配而在队列中等候的最大请求数,超过这个请求数的用户连接就不会被接受
DBCP的bug非常多,因此Hibernate3已经不再支持DBCP连接池,而推荐使用C3PO。建议你更换数据库连接池。
然后跑去Hibernate官方论坛看,果然,在Please migrate away
from DBCP看到Gavin说:
引用:
Guys, after many problems with DBCP, I have decided to remove built-in
support for DBCP from Hibernate3, and deprecate DBCP in Hibernate 2.1.
I advise everyone to migrate away from DBCP to something that actually
works, like C3P0 or Proxool.
(If you /must/ use DBCP, you can always write your own connection
provider.)
Actually, it is probably about time we remove any remaining
dependencies to Apache commons stuff, since historically they have
caused just /so/ much trouble. The only Apache things that do seem to
work very well are Ant and log4j. Even commons-logging is a PIA,
especially in Tomcat.
C3P0是Hibernate3.0默认的自带数据库连接池,DBCP是Apache开发的数据库连接池。我们对这两种连接池进行压力测试对比,发现在并发30 0个用户以下时,DBCP比C3P0平均时间快1秒左右。但在并发400个用户时,两者差不多。
速度上虽然DBCP比C3P0快些,但是有BUG:当DBCP建立的数据库连接,因为某种原因断掉后,DBCP将不会再重新创建新的连接,导致必须重新启动To mcat才能解决问题。DBCP的BUG使我们决定采用C3P0作为数据库连接池。
///////////////////////////////////////////////////////////////////////////////////////////