一、自定義數(shù)據(jù)庫(kù)連接池實(shí)現(xiàn)思想
依賴的jar
依賴的jar包

依賴的jar包
1、思想步驟
- 1、鏈接池類
- 2、制定全局參數(shù),初始化數(shù)目,最大連接數(shù),當(dāng)前連接,鏈接池集合
- 3、構(gòu)造函數(shù)循環(huán)創(chuàng)建3個(gè)鏈接
- 4、寫一個(gè)從創(chuàng)建連接的方法
- 5、獲取連接
判斷有鏈接直接拿
是否達(dá)到最大連接數(shù),達(dá)到拋出異常
沒達(dá)到創(chuàng)建新連接 - 6、釋放鏈接 放回集合中
- 7、優(yōu)化連接 擴(kuò)展close()方法 動(dòng)態(tài)代理
2、思想原理圖
原理圖

原理圖
3、優(yōu)化:
當(dāng)關(guān)閉連接時(shí)候把鏈接放入連接池 就是調(diào)用clos()方法觸發(fā)releaseConnection(Connection conn)方法
*解決1:繼承Connection重寫clos方法 方法太多不可行
*解決2:動(dòng)態(tài)代理
如果對(duì)某個(gè)接口中得到某個(gè)方法進(jìn)行擴(kuò)展,而不想實(shí)現(xiàn)接口所有的方法可以使用的動(dòng)態(tài)代理模式
java中代理模塊:靜態(tài),動(dòng)態(tài),cglib代理
動(dòng)態(tài)代理可以及檢測(cè)接口中方法的執(zhí)行
如何生成動(dòng)態(tài)代理 jdk API提供Proxy
static Object newProxyInstance{
ClassLoader loader //當(dāng)前使用的類加載器
Class<?>interface //目標(biāo)對(duì)象Connection實(shí)現(xiàn)的接口類型
InvocationHabdler h //事件處理器,當(dāng)執(zhí)行上面接口中的方法的時(shí)候, 就自動(dòng)觸發(fā)處理器方法,把當(dāng)前執(zhí)行的發(fā)方法(method)作為參數(shù)傳入
}
二、代碼實(shí)現(xiàn)
1、定義獲取連接的接口DataSource.java
package work.doudou.MyPool;
import java.sql.Connection;
//定義獲取連接的接口
public interface DataSource {
public Connection getConnection();
}
2、數(shù)據(jù)源BasicDataSource.java
package work.doudou.MyPool;
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.util.LinkedList;
/**
* 自定義鏈接池
* 1、MyPool.java類,鏈接池類
* 2、制定全局參數(shù),初始化數(shù)目,最大連接數(shù),當(dāng)前連接,鏈接池集合
* 3、構(gòu)造函數(shù)循環(huán)創(chuàng)建3個(gè)鏈接
* 4、寫一個(gè)從創(chuàng)建連接的方法
* 5、獲取連接
* 判斷有鏈接直接拿
* 是否達(dá)到最大連接數(shù),達(dá)到拋出異常
* 沒達(dá)到創(chuàng)建新連接
* 6、釋放鏈接 放回集合中
* 7、優(yōu)化連接 擴(kuò)展close()方法 動(dòng)態(tài)代理
**/
/* 優(yōu)化:
* 當(dāng)關(guān)閉連接時(shí)候把鏈接放入連接池 就是調(diào)用clos()方法觸發(fā)releaseConnection(Connection conn)方法
* 解決1:繼承Connection重寫clos方法 方法太多不可行
* 解決2:動(dòng)態(tài)代理
* 如果對(duì)某個(gè)接口中得到某個(gè)方法進(jìn)行擴(kuò)展,而不想實(shí)現(xiàn)接口所有的方法可以使用的動(dòng)態(tài)代理模式
* java中代理模塊:靜態(tài),動(dòng)態(tài),cglib代理
* 動(dòng)態(tài)代理可以及檢測(cè)接口中方法的執(zhí)行
* 如何生成動(dòng)態(tài)代理 jdk API提供Proxy
* static Object newProxyInstance{
* ClassLoader loader 當(dāng)前使用的類加載器
* Class<?>interface 目標(biāo)對(duì)象Connection實(shí)現(xiàn)的接口類型
* InvocationHabdler h 事件處理器,當(dāng)執(zhí)行上面接口中的方法的時(shí)候,就自動(dòng)觸發(fā)
* 處理器方法,把當(dāng)前執(zhí)行的發(fā)方法(method)作為參數(shù)傳入
* }
*/
public class BasicDataSource implements DataSource{
//數(shù)據(jù)庫(kù)連接賬號(hào)
private String username=null;
//數(shù)據(jù)庫(kù)連接密碼
private String password=null;
//驅(qū)動(dòng)com.mysql.jdbc.Driver
private String driver=null;
//數(shù)據(jù)庫(kù)連接url jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8","root","root
private String url=null;
//初始化數(shù)目
private int init_count=3;
//最大連接數(shù)
private int max_count=5;
//連接池里頭的連接
private int current_count=0;
//連接池,存放鏈接
private LinkedList<Connection> connections=new LinkedList<Connection>();
//1、初始化連接放入連接池
private void createBasicDataSource(){
//初始化連接
for(int i=0;i<init_count;i++){
//記錄當(dāng)前連接數(shù)
current_count++;
//把鏈接放入連接池
connections.addLast(createConnection());
}
}
//2、建新連接的方法
private Connection createConnection(){
try {
Class.forName(driver);
//原始的目標(biāo)對(duì)象
final Connection conn= DriverManager.getConnection(url,username,password);
/*******創(chuàng)建代理對(duì)象********/
//創(chuàng)建代理對(duì)象
Connection proxyConnection=(Connection)Proxy.newProxyInstance(
//類加載器
conn.getClass().getClassLoader(),
//目標(biāo)接口對(duì)象
new Class[] {Connection.class},
//當(dāng)調(diào)用conn對(duì)象的時(shí)候自動(dòng)觸發(fā)事務(wù)處理器
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//方法返回值
Object result=null;
//當(dāng)前執(zhí)行的方法名
String methoName=method.getName();
//判斷執(zhí)行close()就把連接放入連接池
if ("close".equals(methoName)) {
//連接放入連接池
if(connections.size()<init_count){
connections.addLast(conn);
}else{
//如果連接池滿了就關(guān)了連接
try {
current_count--;
conn.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}else{
//調(diào)用目標(biāo)方法對(duì)象
result=method.invoke(conn, args);
}
return result;
}
});
return proxyConnection;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
//3、獲取連接
@Override
public Connection getConnection() {
//獲取連接之前判斷是否初始化
if (connections.size()<=0) {
createBasicDataSource();
}
//判斷是否連接,有就去出,,就直拿
if (connections.size()>0) {
return connections.removeFirst();
}
//判斷連接池有沒有連接,如果沒有達(dá)到最大連接,就創(chuàng)建
if (current_count<max_count) {
//記錄當(dāng)前連接使用數(shù)
current_count++;
//創(chuàng)建連接
return createConnection();
}
//如果已達(dá)到最大連接數(shù)就,就拋出異常
throw new RuntimeException("當(dāng)前連接已達(dá)到最大連接數(shù)目!");
}
//4、釋放鏈接
public void releaseConnection(Connection conn) {
//判斷當(dāng)前連接池?cái)?shù)目如果少于初始化就放入池中
if(connections.size()<init_count){
connections.addLast(conn);
}else{
//如果連接池滿了就關(guān)了連接
try {
current_count--;
conn.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getDriver() {
return driver;
}
public void setDriver(String driver) {
this.driver = driver;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public int getInit_count() {
return init_count;
}
public void setInit_count(int init_count) {
this.init_count = init_count;
}
public int getMax_count() {
return max_count;
}
public void setMax_count(int max_count) {
this.max_count = max_count;
}
public int getCurrent_count() {
return current_count;
}
public LinkedList<Connection> getConnections() {
return connections;
}
}
3、測(cè)試類test.java
package work.doudou.MyPool;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class test {
//創(chuàng)建數(shù)據(jù)庫(kù)連接池基礎(chǔ)數(shù)據(jù)源的對(duì)象
static BasicDataSource pool=new BasicDataSource();
//設(shè)置基礎(chǔ)數(shù)據(jù)
static{
pool.setUsername("root");
pool.setPassword("root");
pool.setDriver("com.mysql.jdbc.Driver");
pool.setUrl("jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8");
pool.setInit_count(5);
pool.setMax_count(7);
}
//返回連接池對(duì)象
public static DataSource getDataSource() {
return pool;
}
//測(cè)試主方法
public static void main(String[] args) {
//獲取數(shù)據(jù)庫(kù)連接
Connection connection=getDataSource().getConnection();
//查詢執(zhí)行器
Statement s=null;
//返回結(jié)果集
ResultSet rs=null;
//控制臺(tái)輸出獲取到連接的地址
System.out.println(connection);
try {
//執(zhí)行查詢
s=connection.createStatement();
rs=s.executeQuery("select * from a");
while (rs.next()) {
System.out.println(rs.getInt("a"));
}
//關(guān)閉結(jié)果集
rs.close();
//關(guān)閉執(zhí)行器
s.close();
//這里關(guān)閉連接是吧連接放回連接池
connection.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("總共的連接數(shù)目"+pool.getCurrent_count());
System.out.println("連接池里空閑的連接"+pool.getConnections().size());
}
}
三、運(yùn)行結(jié)果

運(yùn)行結(jié)果