C3P0在最近的demo中也用了(我用的是0.9.2.1版本),因为单例很难应付大量并发。
用法详见文档:http://www.mchange.com/projects/c3p0/
基本的用法在http://www.mchange.com/projects/c3p0/#quickstart,
以及http://www.mchange.com/projects/c3p0/#using_c3p0中。
在项目中更为方便的做法是将配置写在配置文件中。
C0P0的配置文件名为c3p0-config.xml,详见http://www.mchange.com/projects/c3p0/#configuration_files
一个示例的配置文件如下:
<?xml version="1.0" encoding="utf-8"?> <c3p0-config> <default-config> <property name="automaticTestTable">t_c3p0_test</property> <property name="checkoutTimeout">10000</property> <property name="idleConnectionTestPeriod">10</property> <property name="initialPoolSize">5</property> <property name="maxIdleTime">600</property> <property name="maxPoolSize">20</property> <property name="minPoolSize">2</property> <property name="maxStatements">60</property> <property name="maxStatementsPerConnection">3</property> <user-overrides user="test-user"> <property name="maxPoolSize">10</property> <property name="minPoolSize">1</property> <property name="maxStatements">0</property> </user-overrides> </default-config> <named-config name="metkb"> <property name="acquireIncrement">20</property> <property name="initialPoolSize">10</property> <property name="minPoolSize">10</property> <property name="maxPoolSize">100</property> <property name="maxStatements">0</property> <property name="maxStatementsPerConnection">10</property> <!-- he's important, but there's only one of him --> <user-overrides user="master-of-the-universe"> <property name="acquireIncrement">1</property> <property name="initialPoolSize">1</property> <property name="minPoolSize">1</property> <property name="maxPoolSize">5</property> <property name="maxStatementsPerConnection">50</property> </user-overrides> </named-config> </c3p0-config>
放在eclipse Web工程的src目录下即可(eclipse会将该目录下的配置文件复制到tomcat的webapps/XXX/WEB-INF/classes下)
一个C3P0的单例的示例代码如下(连接池的单例并不妨碍并发,因为从连接池中取连接并不费时,而且取出的连接是线程安全的):
package cn.edu.ruc.metkb.util; import java.beans.PropertyVetoException; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import com.mchange.v2.c3p0.ComboPooledDataSource; public class PooledDBA implements DBA { private ComboPooledDataSource cpds = null; private static Log dblog = null; private static String DBClassName = null; private static String DBName = null; private static String DBUrl = null; private static String DBUser = null; private static String DBPassword = null; protected PooledDBA() { cpds = new ComboPooledDataSource("metkb"); try { cpds.setDriverClass(DBClassName); } catch (PropertyVetoException e) { dblog.exception(e); } cpds.setJdbcUrl(DBUrl + DBName); cpds.setUser(DBUser); cpds.setPassword(DBPassword); } static { try { DBClassName = ConfigFactory.getInstance().get("db.classname"); DBName = ConfigFactory.getInstance().get("db.name"); DBUrl = ConfigFactory.getInstance().get("db.url"); DBUser = ConfigFactory.getInstance().get("db.user"); DBPassword = ConfigFactory.getInstance().get("db.password"); dblog = LogFactory.getInstance().getLog("db"); } catch (Exception e) { e.printStackTrace(); } } @Override public synchronized Connection getConnection() throws SQLException, ClassNotFoundException, InterruptedException { return cpds.getConnection(); } @Override public synchronized void close(Connection conn) { try { if (conn != null) { conn.close(); conn = null; } } catch (SQLException e) { dblog.exception(e); } } @Override public synchronized void close(Statement stat) { try { if (stat != null) { stat.close(); stat = null; } } catch (SQLException e) { dblog.exception(e); } } @Override public synchronized void close(ResultSet rest) { try { if (rest != null) { rest.close(); rest = null; } } catch (SQLException e) { dblog.exception(e); } } }