package com.lizard.fastdb.connection.c3p0; import java.sql.Connection; import java.sql.SQLException; import java.util.Properties; import javax.transaction.TransactionManager; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.enhydra.jdbc.standard.StandardXADataSource; import com.lizard.fastdb.connection.ConfigureReflect; import com.lizard.fastdb.connection.ConnectionProvider; import com.lizard.fastdb.datasource.DataSourceUtil; import com.mchange.v2.c3p0.C3P0Registry; import com.mchange.v2.c3p0.ComboPooledDataSource; import com.mchange.v2.c3p0.DataSources; /** * ConnectionProvicer 的 C3P0 实现 * * @author SHEN.GANG */ public class C3P0ConnectionProvider implements ConnectionProvider { private static final long serialVersionUID = 1L; private static final Log logger = LogFactory.getLog(C3P0ConnectionProvider.class); private Properties ds = null; // 数据源配置 private String name = null; // 数据源名称 private ComboPooledDataSource cpds = null; // 当前ConnectionProvider对应的C3P0数据源 /** * 配置连接池 */ public void configure(Properties ds) { if (this.ds != null) { return; } this.ds = ds; this.name = this.ds.getProperty("name"); if (!isDataSourcePooled(name)) { logger.info("Initializing C3P0 pool [" + name + "]..."); convertToC3P0DataSource(); } } /** * 从连接池中获得一个连接 */ public Connection getConnection() throws SQLException { return cpds.getConnection(); } /** * 根据指定的数据源获得该数据源的事务Connection对象,并将其设置给指定的事务管理器管理 * * @param tm 事务管理器 * @return 由XAConnection创建的Connection对象 * @throws SQLException */ public Connection getXAConnection(TransactionManager tm) throws SQLException { StandardXADataSource sxd = DataSourceUtil.convertPropertiesToXADataSource(ds); sxd.setTransactionManager(tm); Connection conn = sxd.getXAConnection().getConnection(); conn.setAutoCommit(false); return conn; } /** * 销毁数据源 */ private void destory() { if (isDataSourcePooled(name)) { try { DataSources.destroy(C3P0Registry.pooledDataSourceByName(name)); logger.info("Destroy C3P0 pool [" + name + "] success!"); } catch (SQLException e) { logger.error("Failed to destroy C3P0 pool [" + name + "]!", e); } } } /** * 关闭当前连接池 */ public void shutdown() { logger.info("Shutdown C3P0 pool [" + name + "] ..."); destory(); // Set ds_set = C3P0Registry.getPooledDataSources(); // if (ds_set != null && ds_set.size() > 0) // { // try // { // for (Object ds : ds_set) // { // logger.info("Destory c3p0 pool [" + ((PooledDataSource) ds).getDataSourceName() + "]"); // DataSources.destroy((PooledDataSource) ds); // } // } // catch (SQLException e) // { // logger.error("Failed to shutdown C3P0 pool!", e); // } // } } /** * 查看指定名称的连接池是否存在 * * @param ds_name 数据源名称 * @return true -- 存在,false -- 不存在 */ private boolean isDataSourcePooled(String ds_name) { return C3P0Registry.pooledDataSourceByName(ds_name) != null; } /** * 关闭指定的数据库连接 * * @param conn 要关闭的数据库连接 */ public void closeConnection(Connection conn) throws SQLException { if (conn != null) { conn.close(); } } /** * 将数据源配置(properties)转换为C3P0的数据源对象 */ private void convertToC3P0DataSource() { cpds = new ComboPooledDataSource(); setAttributeMapping(); try { ConfigureReflect.setProperties(cpds, ds); // 由于C3P0的设计策略是:只有当程序第一次使用Connection时,才真正的创建连接池 // 所以这里需要根据配置采用手工方式触发创建真正连接池 if (Boolean.valueOf(ds.getProperty("load-on-startup"))) { // 获取一个连接,然后立刻关闭它,作用: 是向C3P0发送一个创建连接池信号 closeConnection(cpds.getConnection()); } } catch (Exception e1) { e1.printStackTrace(); } } /** * 设置属性映射,用于通过方法反射设置属性 */ private void setAttributeMapping() { // 以下属性不支持 // available-connection-size this.ds.setProperty("driverClass", this.ds.getProperty("driver-class")); this.ds.setProperty("dataSourceName", name); this.ds.setProperty("jdbcUrl", this.ds.getProperty("driver-url")); this.ds.setProperty("maxPoolSize", this.ds.getProperty("max-connection-size")); this.ds.setProperty("minPoolSize", this.ds.getProperty("min-connection-size")); this.ds.setProperty("initialPoolSize", this.ds.getProperty("init-connection-size")); this.ds.setProperty("maxIdleTime", this.ds.getProperty("max-connection-idletime")); this.ds.setProperty("maxConnectionAge", this.ds.getProperty("max-connection-lifetime")); this.ds.setProperty("acquireIncrement", this.ds.getProperty("acquire-increment-size")); this.ds.setProperty("acquireRetryDelay", this.ds.getProperty("acquire-retry-delay")); this.ds.setProperty("acquireRetryAttempts", this.ds.getProperty("acquire-retry-attempts")); this.ds.setProperty("testConnectionOnCheckin", this.ds.getProperty("test-connection-checkin")); this.ds.setProperty("testConnectionOnCheckout", this.ds.getProperty("test-connection-checkout")); this.ds.setProperty("preferredTestQuery", this.ds.getProperty("test-sql")); this.ds.setProperty("idleConnectionTestPeriod", this.ds.getProperty("idle-connection-test-period")); this.ds.setProperty("loginTimeout", this.ds.getProperty("connection-timeout")); } }