Java中JDBC連接池的基本原理及實(shí)現(xiàn)方式
一、 應(yīng)用程序直接建立數(shù)據(jù)庫連接模型
應(yīng)用程序直接每次訪問數(shù)據(jù)庫時(shí),都建立創(chuàng)建一個(gè)數(shù)據(jù)庫的鏈接,這樣每次建立這樣的連接都需要耗費(fèi)的資源,當(dāng)同時(shí)有很多用戶在使用應(yīng)用程序時(shí),可能會(huì)導(dǎo)致應(yīng)用程序崩潰。
圖為應(yīng)用程序直接建立數(shù)據(jù)庫連接模型

二、使用數(shù)據(jù)庫連接池優(yōu)化模型
數(shù)據(jù)庫連接池的基本思路是,平時(shí)建立適量的數(shù)據(jù)庫的連接,放在一個(gè)集合中,當(dāng)有用戶需要建立數(shù)據(jù)庫連接的時(shí)候,直接到集合中取出一個(gè)數(shù)據(jù)庫連接對(duì)象(Connection),這樣不用再需要重新創(chuàng)建,這樣會(huì)節(jié)省大量的資源,當(dāng)用戶不需要在對(duì)數(shù)據(jù)庫進(jìn)行訪問了,那么就將數(shù)據(jù)庫連接對(duì)象(Connection)重新放回到集合中,以便方便下次使用。
數(shù)據(jù)庫連接池優(yōu)化模型圖

1、關(guān)于連接池中的連接數(shù)量的一些規(guī)定:
- (1)最小連接數(shù):是連接池一直保持的數(shù)據(jù)庫連接,所以如果應(yīng)用程序?qū)?shù)據(jù)庫連接的使用量不大,將會(huì)有大量的數(shù)據(jù)庫連接資源被浪費(fèi)(適量).
- (2)最大連接數(shù):是連接池能申請(qǐng)的最大連接數(shù),如果數(shù)據(jù)庫連接請(qǐng)求超過次數(shù),后面的數(shù)據(jù)庫連接請(qǐng)求將被加入到等待隊(duì)列中,這會(huì)影響以后的數(shù)據(jù)庫操作。通常在使用完起始集合中的連接后,會(huì)再重新創(chuàng)建一些數(shù)據(jù)庫連接對(duì)象,用來滿足用戶需求,但是這種新建并不是無限制的。
- (3)當(dāng)使用完的連接對(duì)象需要重新放回到集合中以備使用,但是超過最小連接數(shù)的連接在使用完不會(huì)馬上被釋放,他將被放到連接池中等待重復(fù)使用或是超時(shí)后最終被釋放。
2、編寫數(shù)據(jù)庫連接池
簡單思路為:創(chuàng)建一個(gè)類繼承DataSource接口,在類中實(shí)現(xiàn)靜態(tài)的加載出配置文檔db.properties文檔,并創(chuàng)建最小連接量的數(shù)據(jù)庫連接對(duì)象(Connection),添加到Linkedlist(選擇Linkedlist集合原因是便于增刪)集合中。重寫getConnection()函數(shù),在getConnection()函數(shù)中實(shí)現(xiàn)數(shù)據(jù)庫連接對(duì)象的獲取。
db.properties文檔
driver=com.mysql.jdbc.Driver url=jdbc:mysql://127.0.0.1:3306/imooc?useUnicode=true&characterEncoding=utf-8 username=root password=tiger jdbcConnectionInitSize=10
創(chuàng)建數(shù)據(jù)庫連接池:
package JDBC;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.LinkedList;
import java.util.Properties;
import java.util.logging.Logger;
import javax.sql.DataSource;
public class JdbcConnectionsPool implements DataSource {
/*
* 使用靜態(tài)塊代碼,初始化連接池,創(chuàng)建連接池的中最小鏈接數(shù)量連接,
* 創(chuàng)建linkedlist集合,將這些連接放入集合中
*/
//創(chuàng)建linkedlist集合
private static LinkedList<Connection> linkedlist1=new LinkedList<Connection>();
private static String driver;//
private static String url;//
private static String username;//數(shù)據(jù)庫登陸名
private static String password;//數(shù)據(jù)庫的登陸密碼
private static int jdbcConnectionInitSize;//最小連接數(shù)量
private static int max=1; //當(dāng)前最大連接數(shù)量=max*jdbcConnectionInitSize
static{
//通過反射機(jī)制獲取訪問db.properties文件
InputStream is=JdbcConnectionsPool.class.getResourceAsStream("/db.properties");
Properties prop=new Properties();
try {
//加載db.properties文件
prop.load(is);
//獲取db.properties文件中的數(shù)據(jù)庫連接信息
driver=prop.getProperty("driver");
url=prop.getProperty("url");
username=prop.getProperty("username");
password=prop.getProperty("password");
jdbcConnectionInitSize=Integer.parseInt(prop.getProperty("jdbcConnectionInitSize"));
Class.forName("com.mysql.jdbc.Driver");
//創(chuàng)建最小連接數(shù)個(gè)數(shù)據(jù)庫連接對(duì)象以備使用
for(int i=0;i<jdbcConnectionInitSize;i++){
Connection conn=DriverManager.getConnection(url, username, password);
System.out.println("獲取到了鏈接" + conn);
//將創(chuàng)建好的數(shù)據(jù)庫連接對(duì)象添加到Linkedlist集合中
linkedlist1.add(conn);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
public PrintWriter getLogWriter() throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public void setLogWriter(PrintWriter out) throws SQLException {
// TODO Auto-generated method stub
}
@Override
public void setLoginTimeout(int seconds) throws SQLException {
// TODO Auto-generated method stub
}
@Override
public int getLoginTimeout() throws SQLException {
// TODO Auto-generated method stub
return 0;
}
@Override
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
// TODO Auto-generated method stub
return null;
}
@Override
public <T> T unwrap(Class<T> iface) throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
// TODO Auto-generated method stub
return false;
}
/*
* 實(shí)現(xiàn)數(shù)據(jù)庫連接的獲取和新創(chuàng)建
*/
@Override
public Connection getConnection() throws SQLException {
//如果集合中沒有數(shù)據(jù)庫連接對(duì)象了,且創(chuàng)建的數(shù)據(jù)庫連接對(duì)象沒有達(dá)到最大連接數(shù)量,可以再創(chuàng)建一組數(shù)據(jù)庫連接對(duì)象以備使用
if(linkedlist1.size()==0&&max<=5){
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
for(int i=0;i<jdbcConnectionInitSize;i++){
Connection conn=DriverManager.getConnection(url, username, password);
System.out.println("獲取到了鏈接" + conn);
//將創(chuàng)建好的數(shù)據(jù)庫連接對(duì)象添加到Linkedlist集合中
linkedlist1.add(conn);
}
max++;
}
if(linkedlist1.size()>0){
//從linkedlist集合中取出一個(gè)數(shù)據(jù)庫鏈接對(duì)象Connection使用
Connection conn1=linkedlist1.removeFirst();
System.out.println("linkedlist1數(shù)據(jù)庫連接池大小是" + linkedlist1.size());
/*返回一個(gè)Connection對(duì)象,并且設(shè)置Connection對(duì)象方法調(diào)用的限制,
*當(dāng)調(diào)用connection類對(duì)象的close()方法時(shí)會(huì)將Connection對(duì)象重新收集放入linkedlist集合中。
*/
return (Connection) Proxy.newProxyInstance(conn1.getClass().getClassLoader(),//這里換成JdbcConnectionsPool.class.getClassLoader();也行
conn1.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if(!method.getName().equalsIgnoreCase("close")){
return method.invoke(conn1, args);
}else{
linkedlist1.add(conn1);
System.out.println(conn1+"對(duì)象被釋放,重新放回linkedlist集合中!");
System.out.println("此時(shí)Linkedlist集合中有"+linkedlist1.size()+"個(gè)數(shù)據(jù)庫連接對(duì)象!");
return null;
}
}
});
}else{
System.out.println("連接數(shù)據(jù)庫失敗!");
}
return null;
}
@Override
public Connection getConnection(String username, String password) throws SQLException {
return null;
}
}
進(jìn)一步封裝一些相關(guān)數(shù)據(jù)庫的類的方法
package JDBC;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class JdbcConnectionPoolTest {
/**
* @Field: pool
* 數(shù)據(jù)庫連接池
*/
private static JdbcConnectionsPool pool = new JdbcConnectionsPool();
/**
* @Method: getConnection
* @Description: 從數(shù)據(jù)庫連接池中獲取數(shù)據(jù)庫連接對(duì)象
* @return Connection數(shù)據(jù)庫連接對(duì)象
* @throws SQLException
*/
public static Connection getConnection() throws SQLException{
return pool.getConnection();
}
/**
* @Method: release
* @Description: 釋放資源,
* 釋放的資源包括Connection數(shù)據(jù)庫連接對(duì)象,負(fù)責(zé)執(zhí)行SQL命令的Statement對(duì)象,存儲(chǔ)查詢結(jié)果的ResultSet對(duì)象
* @param conn
* @param st
* @param rs
*/
public static void release(Connection conn,Statement st,ResultSet rs){
if(rs!=null){
try{
//關(guān)閉存儲(chǔ)查詢結(jié)果的ResultSet對(duì)象
rs.close();
}catch (Exception e) {
e.printStackTrace();
}
rs = null;
}
if(st!=null){
try{
//關(guān)閉負(fù)責(zé)執(zhí)行SQL命令的Statement對(duì)象
st.close();
}catch (Exception e) {
e.printStackTrace();
}
}
if(conn!=null){
try{
//關(guān)閉Connection數(shù)據(jù)庫連接對(duì)象
conn.close();
}catch (Exception e) {
e.printStackTrace();
}
}
}
}
調(diào)試代碼:
package JDBC;
import java.sql.Blob;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
public class TestJdbcPool {
public static void main(String[] args) throws SQLException {
//實(shí)例化封裝了有關(guān)數(shù)據(jù)庫類方法類的對(duì)象
JdbcConnectionPoolTest jcpt=new JdbcConnectionPoolTest();
//獲得數(shù)據(jù)庫連接對(duì)象
Connection conn=jcpt.getConnection();
//下面代碼是存儲(chǔ)過程的調(diào)用
String s="call SP_select_nofilter6(?,?,?) ";
CallableStatement cst=conn.prepareCall(s);
cst.setInt(2, 2);
cst.registerOutParameter(1, Types.VARCHAR);
cst.registerOutParameter(3, Types.BLOB);
ResultSet rs=cst.executeQuery();
String name=cst.getString(1);
Blob b=cst.getBlob(3);
System.out.println("name:"+name+" Blob:"+b);
//關(guān)閉所有的數(shù)據(jù)庫資源
jcpt.release(conn, cst, rs);
}
}
運(yùn)行結(jié)果:
獲取到了鏈接com.mysql.jdbc.Connection@5f184fc6 獲取到了鏈接com.mysql.jdbc.Connection@723279cf 獲取到了鏈接com.mysql.jdbc.Connection@4e50df2e 獲取到了鏈接com.mysql.jdbc.Connection@7cc355be 獲取到了鏈接com.mysql.jdbc.Connection@52cc8049 獲取到了鏈接com.mysql.jdbc.Connection@7530d0a 獲取到了鏈接com.mysql.jdbc.Connection@4fca772d 獲取到了鏈接com.mysql.jdbc.Connection@7cd84586 獲取到了鏈接com.mysql.jdbc.Connection@70177ecd 獲取到了鏈接com.mysql.jdbc.Connection@cc34f4d linkedlist1數(shù)據(jù)庫連接池大小是9 name:xiao Blob:com.mysql.jdbc.Blob@5197848c com.mysql.jdbc.Connection@5f184fc6對(duì)象被釋放,重新放回linkedlist集合中! 此時(shí)Linkedlist集合中有10個(gè)數(shù)據(jù)庫連接對(duì)象!
標(biāo)紅的代碼是比較重要的代碼段~,其中Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h),返回一個(gè)指定接口的代理類實(shí)例,該接口可以將方法調(diào)用指派到指定的調(diào)用處理程序,loader參數(shù)定義代理類的類加載器,interfaces - 代理類要實(shí)現(xiàn)的接口列表,h - 指派方法調(diào)用的調(diào)用處理程序 。
三、兩個(gè)開源的數(shù)據(jù)庫連接池
在使用了數(shù)據(jù)庫連接池之后,在項(xiàng)目的實(shí)際開發(fā)中就不需要編寫連接數(shù)據(jù)庫的代碼了,直接從數(shù)據(jù)源獲得數(shù)據(jù)庫的連接。
1、dbcp連接
(1)導(dǎo)入相關(guān)jar包
commons-dbcp2-2.1.1.jar
commons-pool2-2.4.2.jar
commoms-logging-1.2.jar
(2)在項(xiàng)目根目錄增加配置文件dbcp.properties
#連接設(shè)置 driverClassName=com.mysql.jdbc.Driver url=jdbc:mysql://localhost:3306/jdbcstudy username=root password=XDP #<!-- 初始化連接 --> initialSize=10 #最大連接數(shù)量 maxActive=50 #<!-- 最大空閑連接 --> maxIdle=20 #<!-- 最小空閑連接 --> minIdle=5 #<!-- 超時(shí)等待時(shí)間以毫秒為單位 6000毫秒/1000等于60秒 --> maxWait=60000 #JDBC驅(qū)動(dòng)建立連接時(shí)附帶的連接屬性屬性的格式必須為這樣:[屬性名=property;] #注意:"user" 與 "password" 兩個(gè)屬性會(huì)被明確地傳遞,因此這里不需要包含他們。 connectionProperties=useUnicode=true;characterEncoding=UTF8 #指定由連接池所創(chuàng)建的連接的自動(dòng)提交(auto-commit)狀態(tài)。 defaultAutoCommit=true #driver default 指定由連接池所創(chuàng)建的連接的只讀(read-only)狀態(tài)。 #如果沒有設(shè)置該值,則“setReadOnly”方法將不被調(diào)用。(某些驅(qū)動(dòng)并不支持只讀模式,如:Informix) defaultReadOnly= #driver default 指定由連接池所創(chuàng)建的連接的事務(wù)級(jí)別(TransactionIsolation)。 #可用值為下列之一:(詳情可見javadoc。)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE defaultTransactionIsolation=READ_UNCOMMITTED
(3)程序?qū)崿F(xiàn)dbcp連接
代碼演示:
數(shù)據(jù)庫對(duì)象的代理類(封裝Connection類的一些方法)
package DBCP;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
import javax.sql.DataSource;
import org.apache.commons.dbcp.BasicDataSourceFactory;
public class DBCPUtil {
private static DataSource ds;
private static final String configFile="/dbcp.properties";
public DBCPUtil(){
//實(shí)例化properties對(duì)象用于加載配置文件
Properties prop=new Properties();
InputStream is=DBCPUtil.class.getResourceAsStream(configFile);
try {
prop.load(is);
ds=BasicDataSourceFactory.createDataSource(prop);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/*
* 獲取數(shù)據(jù)庫連接對(duì)象
*/
public Connection getConn(){
Connection conn=null;
if(ds!=null){
try {
conn=ds.getConnection();
conn.setAutoCommit(false);//設(shè)置禁止操作自動(dòng)提交的情況
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return conn;
}
return conn;
}
/*
* 封裝數(shù)據(jù)庫相關(guān)資源的關(guān)閉工作
*/
public void close(ResultSet rs,Statement st,Connection conn) throws SQLException{
if(rs!=null){
rs.close();
}
if(st!=null){
st.close();
}
if(conn!=null){
conn.close();
}
}
}
代碼調(diào)用:
package DBCP;
import java.sql.Blob;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
public class DbcpTest {
public static void main(String[] args) throws SQLException {
//實(shí)例化數(shù)據(jù)庫連接的代理類
DBCPUtil dbcpUtil=new DBCPUtil();
//獲得數(shù)據(jù)庫連接對(duì)象
Connection conn=dbcpUtil.getConn();
//下面代碼是存儲(chǔ)過程的調(diào)用
String s="call SP_select_nofilter6(?,?,?) ";
CallableStatement cst=conn.prepareCall(s);
cst.setInt(2, 2);
cst.registerOutParameter(1, Types.VARCHAR);
cst.registerOutParameter(3, Types.BLOB);
ResultSet rs=cst.executeQuery();
String name=cst.getString(1);
Blob b=cst.getBlob(3);
System.out.println("name:"+name+" Blob:"+b);
//關(guān)閉資源
dbcpUtil.close(rs, cst, conn);
}
}
運(yùn)行結(jié)果:
name:xiao Blob:com.mysql.jdbc.Blob@30946e09
2、c3p0連接池
c3p0是一個(gè)開源的JDBC連接池,它實(shí)現(xiàn)了數(shù)據(jù)源和JNDI綁定支持JDBC3和JDBC2的標(biāo)準(zhǔn)擴(kuò)展
(1)導(dǎo)入相關(guān)的jar包
cc3p0-0.9.2-pre4.jar
mchange-commons-java-0.2.2.jar
如果是oracle數(shù)據(jù)庫還需要添加c3p0-oracle-thin-extras-0.9.2-pre1.jar
(2)在項(xiàng)目根目錄下增加配置文件
1)c3p0.properties
##配置除user,password,minpoolsize,maxpoolsize的參數(shù) ##[注意] 整數(shù)值不能有空格 #連接設(shè)置 driverClassName=com.mysql.jdbc.Driver url=jdbc:mysql://127.0.0.1:3306/imooc?useUnicode=true&characterEncoding=utf-8 username=root password=tiger #初始化時(shí)獲取三個(gè)連接,取值應(yīng)在minPoolSize與maxPoolSize之間。Default: 3 c3p0.initialPoolSize=10 #當(dāng)連接池中的連接耗盡的時(shí)候c3p0一次同時(shí)獲取的連接數(shù)。Default: 3 c3p0.acquireIncrement=3 #最大空閑時(shí)間,60秒內(nèi)未使用則連接被丟棄。若為0則永不丟棄。Default: 0 #maxIdleTime應(yīng)該小于MySQL的wait_timeout的值 c3p0.maxIdleTime=600 #定義在從數(shù)據(jù)庫獲取新連接失敗后重復(fù)嘗試的次數(shù)。Default: 30 c3p0.acquireRetryAttempts=5 #兩次連接中間隔時(shí)間,單位毫秒。Default: 1000 c3p0.acquireRetryDelay=1000 #連接關(guān)閉時(shí)默認(rèn)將所有未提交的操作回滾。Default: false c3p0.autoCommitOnClose=false #c3p0將建一張名為Test的空表,并使用其自帶的查詢語句進(jìn)行測(cè)試。如果定義了這個(gè)參數(shù)那么 #屬性preferredTestQuery將被忽略。你不能在這張Test表上進(jìn)行任何操作,它將只供c3p0測(cè)試 #使用。Default: null #c3p0.automaticTestTable= #獲取連接失敗將會(huì)引起所有等待連接池來獲取連接的線程拋出異常。但是數(shù)據(jù)源仍有效 #保留,并在下次調(diào)用getConnection()的時(shí)候繼續(xù)嘗試獲取連接。如果設(shè)為true,那么在嘗試 #獲取連接失敗后該數(shù)據(jù)源將申明已斷開并永久關(guān)閉。Default: false #c3p0.breakAfterAcquireFailure=false #當(dāng)連接池用完時(shí)客戶端調(diào)用getConnection()后等待獲取新連接的時(shí)間,超時(shí)后將拋出 #SQLException,如設(shè)為0則無限期等待。單位毫秒。Default: 0 c3p0.checkoutTimeout=10000 #每60秒檢查所有連接池中的空閑連接。Default: 0 c3p0.idleConnectionTestPeriod=600 #JDBC的標(biāo)準(zhǔn)參數(shù),用以控制數(shù)據(jù)源內(nèi)加載的PreparedStatements數(shù)量。但由于預(yù)緩存的statements #屬于單個(gè)connection而不是整個(gè)連接池。所以設(shè)置這個(gè)參數(shù)需要考慮到多方面的因素。 #如果maxStatements與maxStatementsPerConnection均為0,則緩存被關(guān)閉。Default: 0 c3p0.maxStatements=100 #maxStatementsPerConnection定義了連接池內(nèi)單個(gè)連接所擁有的最大緩存statements數(shù)。Default: 0 c3p0.maxStatementsPerConnection=0 #c3p0是異步操作的,緩慢的JDBC操作通過幫助進(jìn)程完成。擴(kuò)展這些操作可以有效的提升性能 #通過多線程實(shí)現(xiàn)多個(gè)操作同時(shí)被執(zhí)行。Default: 3 c3p0.numHelperThreads=3
2)c3p0-config.xml文檔
<?xml version="1.0" encoding="UTF-8"?>
<!--
c3p0-config.xml必須位于類路徑下面
private static ComboPooledDataSource ds;
static{
try {
ds = new ComboPooledDataSource("MySQL");
} catch (Exception e) {
throw new ExceptionInInitializerError(e);
}
}
-->
<c3p0-config>
<!--
C3P0的缺省(默認(rèn))配置,
如果在代碼中“ComboPooledDataSource ds = new ComboPooledDataSource();”這樣寫就表示使用的是C3P0的缺省(默認(rèn))配置信息來創(chuàng)建數(shù)據(jù)源
-->
<default-config>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://127.0.0.1:3306/imooc?useUnicode=true&characterEncoding=utf-8</property>
<property name="user">root</property>
<property name="password">tiger</property>
<property name="acquireIncrement">5</property>
<property name="initialPoolSize">10</property>
<property name="minPoolSize">5</property>
<property name="maxPoolSize">20</property>
</default-config>
<!--
C3P0的命名配置,
如果在代碼中“ComboPooledDataSource ds = new ComboPooledDataSource("MySQL");”這樣寫就表示使用的是name是MySQL的配置信息來創(chuàng)建數(shù)據(jù)源
-->
<named-config name="MySQL">
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://127.0.0.1:3306/imooc?useUnicode=true&characterEncoding=utf-8</property>
<property name="user">root</property>
<property name="password">tiger</property>
<property name="acquireIncrement">5</property>
<property name="initialPoolSize">10</property>
<property name="minPoolSize">5</property>
<property name="maxPoolSize">20</property>
</named-config>
</c3p0-config>
(3)編寫類文件,創(chuàng)建連接池
1)c3p0.properties配置文件情況下
數(shù)據(jù)庫對(duì)象的代理類(封裝Connection類的一些方法)
package C3P0;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import com.mchange.v2.c3p0.ComboPooledDataSource;
public class C3P0Util {
private static ComboPooledDataSource ds=new ComboPooledDataSource();
/*
* 獲取數(shù)據(jù)庫連接對(duì)象
*/
public static Connection getConnection() throws SQLException{
return ds.getConnection();
}
/*
* 封裝數(shù)據(jù)庫相關(guān)資源的關(guān)閉工作
*/
public void close(ResultSet rs,Statement st,Connection conn) throws SQLException{
if(rs!=null){
rs.close();
}
if(st!=null){
st.close();
}
if(conn!=null){
conn.close();
}
}
}
代碼調(diào)用:
package C3P0;
import java.sql.Blob;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
public class C3P0Test {
public static void main(String[] args) throws SQLException {
C3P0Util c3p0Util=new C3P0Util();
Connection conn=c3p0Util.getConnection();
//下面代碼是存儲(chǔ)過程的調(diào)用
String s="call SP_select_nofilter6(?,?,?) ";
CallableStatement cst=conn.prepareCall(s);
cst.setInt(2, 2);
cst.registerOutParameter(1, Types.VARCHAR);
cst.registerOutParameter(3, Types.BLOB);
ResultSet rs=cst.executeQuery();
String name=cst.getString(1);
Blob b=cst.getBlob(3);
System.out.println("name:"+name+" Blob:"+b);
//關(guān)閉資源
c3p0Util.close(rs, cst, conn);
}
}
運(yùn)行結(jié)果:
二月 14, 2017 7:36:12 下午 com.mchange.v2.log.MLog
信息: MLog clients using java 1.4+ standard logging.
二月 14, 2017 7:36:13 下午 com.mchange.v2.c3p0.C3P0Registry
信息: Initializing c3p0-0.9.5.2 [built 08-December-2015 22:06:04 -0800; debug? true; trace: 10]
二月 14, 2017 7:36:13 下午 com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource
信息: Initializing c3p0 pool... com.mchange.v2.c3p0.ComboPooledDataSource [ acquireIncrement -> 3, acquireRetryAttempts -> 5, acquireRetryDelay -> 1000, autoCommitOnClose -> false, automaticTestTable -> null, breakAfterAcquireFailure -> false, checkoutTimeout -> 10000, connectionCustomizerClassName -> null, connectionTesterClassName -> com.mchange.v2.c3p0.impl.DefaultConnectionTester, contextClassLoaderSource -> caller, dataSourceName -> 2y4pm69mgrekqw18rvmvn|7aec35a, debugUnreturnedConnectionStackTraces -> false, description -> null, driverClass -> com.mysql.jdbc.Driver, extensions -> {}, factoryClassLocation -> null, forceIgnoreUnresolvedTransactions -> false, forceSynchronousCheckins -> false, forceUseNamedDriverClass -> false, identityToken -> 2y4pm69mgrekqw18rvmvn|7aec35a, idleConnectionTestPeriod -> 600, initialPoolSize -> 10, jdbcUrl -> jdbc:mysql://127.0.0.1:3306/imooc?useUnicode=true&characterEncoding=utf-8, maxAdministrativeTaskTime -> 0, maxConnectionAge -> 0, maxIdleTime -> 600, maxIdleTimeExcessConnections -> 0, maxPoolSize -> 15, maxStatements -> 100, maxStatementsPerConnection -> 0, minPoolSize -> 3, numHelperThreads -> 3, preferredTestQuery -> null, privilegeSpawnedThreads -> false, properties -> {user=******, password=******}, propertyCycle -> 0, statementCacheNumDeferredCloseThreads -> 0, testConnectionOnCheckin -> false, testConnectionOnCheckout -> false, unreturnedConnectionTimeout -> 0, userOverrides -> {}, usesTraditionalReflectiveProxies -> false ]
name:xiao Blob:com.mysql.jdbc.Blob@31b7dea0
2)c3p0-config.xml配置文檔情況下
數(shù)據(jù)庫對(duì)象的代理類(封裝Connection類的一些方法)
package C3P0;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import com.mchange.v2.c3p0.ComboPooledDataSource;
public class C3P0Util1 {
private static ComboPooledDataSource ds;
/*
* 獲取數(shù)據(jù)庫連接對(duì)象
*/
public static Connection getConnection() throws SQLException{
//通過代碼創(chuàng)建C3P0數(shù)據(jù)庫連接池
/*ds = new ComboPooledDataSource();
ds.setDriverClass("com.mysql.jdbc.Driver");
ds.setJdbcUrl("jdbc:mysql://localhost:3306/jdbcstudy");
ds.setUser("root");
ds.setPassword("XDP");
ds.setInitialPoolSize(10);
ds.setMinPoolSize(5);
ds.setMaxPoolSize(20);*/
//通過讀取C3P0的xml配置文件創(chuàng)建數(shù)據(jù)源,C3P0的xml配置文件c3p0-config.xml必須放在src目錄下
//ds = new ComboPooledDataSource();//使用C3P0的默認(rèn)配置來創(chuàng)建數(shù)據(jù)源
ds = new ComboPooledDataSource("MySQL");//使用C3P0的命名配置來創(chuàng)建數(shù)據(jù)源
return ds.getConnection();
}
/*
* 封裝數(shù)據(jù)庫相關(guān)資源的關(guān)閉工作
*/
public void close(ResultSet rs,Statement st,Connection conn) throws SQLException{
if(rs!=null){
rs.close();
}
if(st!=null){
st.close();
}
if(conn!=null){
conn.close();
}
}
}
代碼調(diào)用:
package C3P0;
import java.sql.Blob;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
public class C3P0Test1 {
public static void main(String[] args) throws SQLException {
C3P0Util1 c3p0Util1=new C3P0Util1();
Connection conn=c3p0Util1.getConnection();
//下面代碼是存儲(chǔ)過程的調(diào)用
String s="call SP_select_nofilter6(?,?,?) ";
CallableStatement cst=conn.prepareCall(s);
cst.setInt(2, 2);
cst.registerOutParameter(1, Types.VARCHAR);
cst.registerOutParameter(3, Types.BLOB);
ResultSet rs=cst.executeQuery();
String name=cst.getString(1);
Blob b=cst.getBlob(3);
System.out.println("name:"+name+" Blob:"+b);
//關(guān)閉資源
c3p0Util1.close(rs, cst, conn);
}
}
運(yùn)行結(jié)果:
二月 14, 2017 8:06:03 下午 com.mchange.v2.log.MLog
信息: MLog clients using java 1.4+ standard logging.
二月 14, 2017 8:06:03 下午 com.mchange.v2.c3p0.C3P0Registry
信息: Initializing c3p0-0.9.5.2 [built 08-December-2015 22:06:04 -0800; debug? true; trace: 10]
二月 14, 2017 8:06:03 下午 com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource
信息: Initializing c3p0 pool... com.mchange.v2.c3p0.ComboPooledDataSource [ acquireIncrement -> 5, acquireRetryAttempts -> 5, acquireRetryDelay -> 1000, autoCommitOnClose -> false, automaticTestTable -> null, breakAfterAcquireFailure -> false, checkoutTimeout -> 10000, connectionCustomizerClassName -> null, connectionTesterClassName -> com.mchange.v2.c3p0.impl.DefaultConnectionTester, contextClassLoaderSource -> caller, dataSourceName -> MySQL, debugUnreturnedConnectionStackTraces -> false, description -> null, driverClass -> com.mysql.jdbc.Driver, extensions -> {}, factoryClassLocation -> null, forceIgnoreUnresolvedTransactions -> false, forceSynchronousCheckins -> false, forceUseNamedDriverClass -> false, identityToken -> 2y4pm69mgsgybs1qf3g8s|6e5e91e4, idleConnectionTestPeriod -> 600, initialPoolSize -> 10, jdbcUrl -> jdbc:mysql://127.0.0.1:3306/imooc?useUnicode=true&characterEncoding=utf-8, maxAdministrativeTaskTime -> 0, maxConnectionAge -> 0, maxIdleTime -> 600, maxIdleTimeExcessConnections -> 0, maxPoolSize -> 20, maxStatements -> 100, maxStatementsPerConnection -> 0, minPoolSize -> 5, numHelperThreads -> 3, preferredTestQuery -> null, privilegeSpawnedThreads -> false, properties -> {user=******, password=******}, propertyCycle -> 0, statementCacheNumDeferredCloseThreads -> 0, testConnectionOnCheckin -> false, testConnectionOnCheckout -> false, unreturnedConnectionTimeout -> 0, userOverrides -> {}, usesTraditionalReflectiveProxies -> false ]
name:xiao Blob:com.mysql.jdbc.Blob@c39f790
總結(jié):其實(shí)不管配置文件是c3p0.properties還是c3p0-config.xml,其代碼實(shí)現(xiàn)部分沒有多大區(qū)別,唯一區(qū)別可能就是c3p0-config.xml情況下可以調(diào)用含參的ComboPooledDataSource(String s)構(gòu)造函數(shù),兩個(gè)都可以調(diào)用其默認(rèn)的無參構(gòu)造函數(shù)。
3、dbcp和c3p0不同之處
| dbcp | c3p0 |
|---|---|
| spring組織推薦使用 | Hibernate組織推薦使用 |
| 強(qiáng)制關(guān)閉連接或者數(shù)據(jù)庫重啟后無法自動(dòng)重連 | 強(qiáng)制關(guān)閉連接或者數(shù)據(jù)庫重啟可以自動(dòng)連接 |
| 沒有自動(dòng)的去回收空閑連接的功能 | 自動(dòng)回收空閑的功能 |
| DBCP提供最大連接數(shù) |
c3p0提供最大空閑時(shí)間 |
| dbcp并沒用相應(yīng)功能 | c3p0可以控制數(shù)據(jù)源加載的prepareedstatement數(shù)量,并且可以設(shè)置幫助線程的數(shù)量來提升JDBC操作速度 |
以上所述是小編給大家介紹的Java中JDBC連接池的基本原理及實(shí)現(xiàn)方式,希望對(duì)大家有所幫助。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
相關(guān)文章
springMVC+velocity實(shí)現(xiàn)仿Datatables局部刷新分頁方法
下面小編就為大家分享一篇springMVC+velocity實(shí)現(xiàn)仿Datatables局部刷新分頁方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-02-02
SpringBoot全局異常捕獲處理實(shí)現(xiàn)方案
這篇文章主要詳細(xì)介紹了SpringBoot全局異常捕獲處理實(shí)現(xiàn)方案,文章通過代碼示例給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下2024-02-02
springboot整合Excel填充數(shù)據(jù)代碼示例
這篇文章主要給大家介紹了關(guān)于springboot整合Excel填充數(shù)據(jù)的相關(guān)資料,文中通過代碼示例介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用springboot具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-08-08
java線程池ExecutorService超時(shí)處理小結(jié)
使用ExecutorService時(shí),設(shè)置子線程執(zhí)行超時(shí)是一個(gè)常見需求,本文就來詳細(xì)的介紹一下ExecutorService超時(shí)的三種方法,感興趣的可以了解一下2024-09-09

