1. 程式人生 > >2018-07-24期 Java動態代理實現數據庫連接池

2018-07-24期 Java動態代理實現數據庫連接池

iter 異常 ... lse system com link 是我 driver

package cn.sjq.proxy.ds.pool;

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.logging.Logger;

import javax.sql.DataSource;

/**

* 使用Java 動態代理實現數據庫連接池Pool

*

* @author songjq

*

*/

public class DataSourcePool implements DataSource {

// 驅動程序名

static String driver = "com.mysql.jdbc.Driver";

// URL指向要訪問的數據庫名mydata

static String url = "jdbc:mysql://hadoop-server03:3306/mysql";

// MySQL配置時的用戶名

static String user = "root";

// MySQL配置時的密碼

static String password = "user#0989";

// 定義一個鏈表保存20個數據庫連接

static LinkedList<Connection> pool = new LinkedList<>();

// 靜態代碼塊

static {

// 加載驅動程序

try {

Class.forName(driver);

for (int i = 0; i < 20; i++) {

pool.add(DriverManager.getConnection(url, user, password));

}

} catch (Exception e) {

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;

}

/**

* 重寫getConnection()方法

*/

@Override

public Connection getConnection() throws SQLException {

/*

* 如果pool長度大於0,說明pool存在連接,將第一個對象返回,否則拋出異常

*/

// 未使用動態代理前

/*

* if(pool.size()>0) { return pool.removeFirst(); }else { throw new

* SQLException("連接池已耗盡,無法分配新的連接..."); }

*/

/**

* 未使用動態代理前,客戶端進行第21次連接的時候就拋出連接池已耗盡的異常,雖然使用conn.close()方法歸還連接,但是該方法是將連接歸還給數據庫,而不是我們定義的pool對象

* 如果要實現調用conn.close()方法後將conn連接對象歸還給pool連接池,就需要使用Java

* 動態代理重寫Connection接口的close()方法。

* 這是客戶端第19次獲得數據庫連接...,連接信息:com.mysql.jdbc.Connection@389922

* 這是客戶端第20次獲得數據庫連接...,連接信息:com.mysql.jdbc.Connection@1cda81e Exception in

* thread "main" java.sql.SQLException: 連接池已耗盡,無法分配新的連接... at

* cn.sjq.proxy.ds.pool.DataSourcePool.getConnection(DataSourcePool.java:101) at

* cn.sjq.proxy.ds.pool.ClientTest.main(ClientTest.java:21)

*/

/**

* 下面使用動態代理重寫Connection接口的close()方法,實現調用close()方法後歸還DataSourcePool連接池的連接。 loader

* - 定義代理類的類加載器 interfaces - 代理類要實現的接口列表 h - 指派方法調用的調用處理程序

* 通過使用動態代理後客戶端可以源源不斷獲得連接,而不是到達20個上限後拋出異常,如下:

* 這是客戶端第25次獲得數據庫連接...,連接信息:com.mysql.jdbc.Connection@1cc5af0

* 這是客戶端第26次獲得數據庫連接...,連接信息:com.mysql.jdbc.Connection@1665a0d

* 這是客戶端第27次獲得數據庫連接...,連接信息:com.mysql.jdbc.Connection@a22e0c

* 這是客戶端第28次獲得數據庫連接...,連接信息:com.mysql.jdbc.Connection@17d51a6

*/

if (pool.size() > 0) {

// 從pool裏面獲取一個連接對象Connection

final Connection conn = pool.removeFirst();

// 使用Java 動態代理重寫Connection中close()方法

Connection newProxyConn = (Connection) Proxy.newProxyInstance(DataSourcePool.class.getClassLoader(),

conn.getClass().getInterfaces(), new InvocationHandler() {

@Override

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

// 重寫close方法

if (method.getName().equals("close")) {

// 回收釋放連接

pool.add(conn);

return null;

} else {

// 其它方法不重寫

return method.invoke(conn, args);

}

}

});

return newProxyConn;

} else {

throw new SQLException("連接池已耗盡,無法分配新的連接...");

}

}

@Override

public Connection getConnection(String username, String password) throws SQLException {

// TODO Auto-generated method stub

return null;

}

}

package cn.sjq.proxy.ds.pool;

import java.sql.Connection;

import java.sql.SQLException;

/**

* 模擬客戶端連接數據

* @author songjq

*

*/

public class ClientTest {

public static void main(String[] args) throws SQLException, InterruptedException {

int count = 0;

//實例化連接池對象DataSourcePool

DataSourcePool pool = new DataSourcePool();

//循環模擬連接數據庫

while(true) {

//獲得一個連接

Connection conn = pool.getConnection();

count++;

//打印連接信息

System.out.println("這是客戶端第"+count+"次獲得數據庫連接...,連接信息:"+conn);

//關閉客戶端連接,將連接歸還連接池

conn.close();

//線程睡眠3秒

Thread.sleep(3000);

}

}

}


2018-07-24期 Java動態代理實現數據庫連接池