自己做数据库连接池c3p0
如何快速使用c3p0 - JDBC3 Connection and Statement Pooling 一、下载 从SourceForge 网站下载最新的版本 http:///projects/c3p0/
二、快速体验 把这一个文件lib/c3p0-0.9.1-pre9.jar复制到你的 CLASSPATH即可。
import com.mchange.v2.c3p0.*; ... ComboPooledDataSource cpds = new ComboPooledDataSource(); cpds.setDriverClass( "org.postgresql.Driver" ); //loads the jdbc driver cpds.setJdbcUrl( "jdbc:postgresql://localhost/testdb" );
cpds.setUser("dbuser"); cpds.setPassword("dbpassword"); 你还可以设置如下参数 cpds.setMaxStatements( 180 ); 然后你就可以从cpds.getConnection()获得连接了。
最后,执行下面语句销毁cpds. DataSources.destroy( cpds );
三、建立自定义连接池工厂 为了适应有多个数据源的单一系统,现在定义在这个系统中使用key字符串来识别每一个数据源,如 oa - 识别 OA 系统 epr - 识别 ERP 系统 hr - 识别 HR 系统 等等 详细代码与注释如下: /////////////////////////////////////////////////////////////// package com.paipaiestore.database.c3p0;
import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Set;
import javax.sql.DataSource;
import com.mchange.v2.c3p0.DataSources; /** * 数据连接池工厂 * @author samland * @version 1.0, 2006-11 */ public class DBPoolFactory {
private static DBPoolFactory dbpoolFactory = new DBPoolFactory(); /** * 连接池列表 */ private static Map poollist = new HashMap();
private DBPoolFactory(){ } public static DBPoolFactory getInstance(){ return dbpoolFactory; } /** * 向连接池列表添加一个新的池化(Pooled)数据源 * @param key * @param configFile 配置文件名。为了简化参数输入与便于外部维护,可以把配置好的文件传入这里分析 */ public void add(String key, String configFile) { //read config from file, and build a dbpool } /** * 向连接池列表添加一个新的池化(Pooled)数据源 * @param key * @param driver 数据连接驱动,如com.mysql.jdbc.Driver * @param url 连接串, 如jdbc:mysql://localhost/samland * @param username 数据库连接用户名,如samland * @param password 数据库连接用户密码 * @throws Exception */ public void add(String key, String driver, String url, String username, String password) throws Exception{ if (key==null) throw new Exception("DBPool ‘key‘ CANNOT be null") ; Class.forName(driver); DataSource ds_unpooled = DataSources.unpooledDataSource(url, username, password); DataSource ds_pooled = DataSources.pooledDataSource( ds_unpooled ); if (poollist.containsKey(key)){ poollist.remove(key); } poollist.put(key, ds_pooled); } /** * 根据key字符串获取连接池 * @param key * @return DBPool 连接池 * @throws Exception */ public DBPool getDBPool(String key) throws Exception{ if (key==null) throw new Exception("DBPool ‘key‘ CANNOT be null") ; DataSource ds = (DataSource)poollist.get(key); DBPool dbpool = new DBPool(); dbpool.setDs_pooled(ds); return dbpool; }
} ///////////////////////////////////////////////////////////////
四、连接池的使用 通过DBPool来获取数据库连接 (jdbc connection)。 4.1 由DBPoolFactory工厂产生一个DBPool 4.2 同时,DBPoolFactory工厂根据传入的参数key向这个DBPool注入数据源 4.3 从DBPool产生线程内的Connection /////////////////////////////////////////////////////////////// package com.paipaiestore.database.c3p0;
import java.sql.Connection; import java.sql.SQLException;
import javax.sql.DataSource;
public class DBPool { /** * 数据库连接。同一个线程使用同一个连接。 */ protected static ThreadLocal connection = new ThreadLocal(); /** * 数据源,需由DBPoolFactory工厂注入 */ private DataSource ds_pooled;
/** * 不能独立构造,必须从DBPoolFactory工厂产生 */ protected DBPool(){} /** * get 数据源 * @return */ public DataSource getDs_pooled() { return ds_pooled; }
/** * 注入数据源 * @param ds_pooled */ public void setDs_pooled(DataSource ds_pooled) { this.ds_pooled = ds_pooled; }
/** * 获得数据库连接 * 同一个线程只返回相同的一个连接。 * @return Connection * @throws SQLException */ public Connection getConnection() throws SQLException{ Connection con = (Connection)connection.get(); if (con==null) { con = ds_pooled.getConnection(); connection.set(con); } return con; } } ///////////////////////////////////////////////////////////////
五、改进线程内数据库连接的使用 为了适应程序已经使用开的jdbc事务管理,因此需要改进DBPool成为Transaction类, 而原来的DBPool则缩减为如下代码: /////////////////////////////////////////////////////////////// public class DBPool { private DataSource ds_pooled; protected DBPool(){} public DataSource getDs_pooled() { return ds_pooled; } public void setDs_pooled(DataSource ds_pooled) { this.ds_pooled = ds_pooled; } } /////////////////////////////////////////////////////////////// package com.paipaiestore.database.c3p0;
import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement;
import javax.sql.DataSource;
public class Transaction { /** * 数据库连接。同一个线程使用同一个连接。 */ protected static ThreadLocal connection = new ThreadLocal(); protected static boolean isInUsed = false; /** * 开始一个事务 * 如果当前线程的数据库连接不存在,则会新获得一个数据库连接 * @param key * @throws Exception */ public static void beginTransaction(String key) throws Exception{ Connection conn = (Connection)connection.get(); if (conn==null) { conn = createConnection(key); setConnection(conn); } conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED); conn.setAutoCommit(false); isInUsed = true; } /** * 提交一个事务 * @throws SQLException */ public static void commitTransaction() throws SQLException { Connection conn = (Connection)connection.get(); conn.commit(); } /** * 回滚一个事务 * @throws SQLException */ public static void rollbackTransaction() throws SQLException { Connection conn = (Connection)connection.get(); conn.rollback(); } public static boolean getIsInUsed() { return isInUsed; } private static void closeConnection() { try { Connection conn = (Connection)connection.get(); if (conn!=null) { connection.set(null); conn.close(); } }catch(SQLException sqlexception) { } } private static void close(ResultSet rs){ try { Statement st = rs.getStatement(); Connection conn = st.getConnection(); rs.close(); st.close(); conn.close(); } catch(Exception exception) { } } /** * 获得数据库连接 * 同一个线程只返回相同的一个连接。 * @return * @throws SQLException */ public static Connection getConnection() throws SQLException { Connection conn = null; conn = (Connection)connection.get(); if(conn == null) throw new NullPointerException(); else return conn; } private static void setConnection(Connection conn){ connection.set(conn); } /** * 获得一个新的数据库连接 * @param key * @return Connection * @throws Exception */ private static Connection createConnection(String key) throws Exception { DBPoolFactory df = DBPoolFactory.getInstance(); DataSource ds_pooled = df.getDBPool(key).getDs_pooled() ; Connection conn = ds_pooled.getConnection(); df = null; return conn; } } /////////////////////////////////////////////////////////////// 六、测试 /////////////////////////////////////////////////////////////// package samland;
import java.sql.Connection; import java.sql.ResultSet; import java.sql.Statement;
import com.paipaiestore.database.c3p0.DBPoolFactory; import com.paipaiestore.database.c3p0.Transaction;
public class TestTransaction { /** * @param args */ public static void main(String[] args) { DBPoolFactory df = DBPoolFactory.getInstance(); Connection con = null; Statement stmt = null; ResultSet rs = null; try { df.add("jxc","com.mysql.jdbc.Driver","jdbc:mysql://paipaiestore.com/samland","samland","*****"); Transaction.beginTransaction("samland"); con = Transaction.getConnection(); stmt = con.createStatement(); rs = stmt.executeQuery("SELECT * FROM users"); while (rs.next()) { System.out.print( rs.getString(1) ); System.out.print( rs.getString(2) ); System.out.println( rs.getString(3) ); } Transaction.commitTransaction(); df = null; } catch (Exception e) { e.printStackTrace(); } } } ///////////////////////////////////////////////////////////////
未经严格测试,请使用者提出修改意见。
下一步需要增加检测当前连接池状态的功能。
|