一、自定義數據庫連接池實現思想
依賴的jar
依賴的jar包
依賴的jar包
1沟蔑、思想步驟
- 1湿诊、鏈接池類
- 2、制定全局參數瘦材,初始化數目厅须,最大連接數,當前連接食棕,鏈接池集合
- 3朗和、構造函數循環(huán)創(chuàng)建3個鏈接
- 4、寫一個從創(chuàng)建連接的方法
- 5簿晓、獲取連接
判斷有鏈接直接拿
是否達到最大連接數眶拉,達到拋出異常
沒達到創(chuàng)建新連接 - 6、釋放鏈接 放回集合中
- 7抢蚀、優(yōu)化連接 擴展close()方法 動態(tài)代理
2镀层、思想原理圖
原理圖
原理圖
3、優(yōu)化:
當關閉連接時候把鏈接放入連接池 就是調用clos()方法觸發(fā)releaseConnection(Connection conn)方法
*解決1:繼承Connection重寫clos方法 方法太多不可行
*解決2:動態(tài)代理
如果對某個接口中得到某個方法進行擴展,而不想實現接口所有的方法可以使用的動態(tài)代理模式
java中代理模塊:靜態(tài)唱逢,動態(tài)吴侦,cglib代理
動態(tài)代理可以及檢測接口中方法的執(zhí)行
如何生成動態(tài)代理 jdk API提供Proxy
static Object newProxyInstance{
ClassLoader loader //當前使用的類加載器
Class<?>interface //目標對象Connection實現的接口類型
InvocationHabdler h //事件處理器,當執(zhí)行上面接口中的方法的時候坞古, 就自動觸發(fā)處理器方法备韧,把當前執(zhí)行的發(fā)方法(method)作為參數傳入
}
二、代碼實現
1痪枫、定義獲取連接的接口DataSource.java
package work.doudou.MyPool;
import java.sql.Connection;
//定義獲取連接的接口
public interface DataSource {
public Connection getConnection();
}
2织堂、數據源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易阳、制定全局參數,初始化數目吃粒,最大連接數潦俺,當前連接,鏈接池集合
* 3徐勃、構造函數循環(huán)創(chuàng)建3個鏈接
* 4事示、寫一個從創(chuàng)建連接的方法
* 5、獲取連接
* 判斷有鏈接直接拿
* 是否達到最大連接數僻肖,達到拋出異常
* 沒達到創(chuàng)建新連接
* 6肖爵、釋放鏈接 放回集合中
* 7、優(yōu)化連接 擴展close()方法 動態(tài)代理
**/
/* 優(yōu)化:
* 當關閉連接時候把鏈接放入連接池 就是調用clos()方法觸發(fā)releaseConnection(Connection conn)方法
* 解決1:繼承Connection重寫clos方法 方法太多不可行
* 解決2:動態(tài)代理
* 如果對某個接口中得到某個方法進行擴展臀脏,而不想實現接口所有的方法可以使用的動態(tài)代理模式
* java中代理模塊:靜態(tài)劝堪,動態(tài),cglib代理
* 動態(tài)代理可以及檢測接口中方法的執(zhí)行
* 如何生成動態(tài)代理 jdk API提供Proxy
* static Object newProxyInstance{
* ClassLoader loader 當前使用的類加載器
* Class<?>interface 目標對象Connection實現的接口類型
* InvocationHabdler h 事件處理器揉稚,當執(zhí)行上面接口中的方法的時候幅聘,就自動觸發(fā)
* 處理器方法,把當前執(zhí)行的發(fā)方法(method)作為參數傳入
* }
*/
public class BasicDataSource implements DataSource{
//數據庫連接賬號
private String username=null;
//數據庫連接密碼
private String password=null;
//驅動com.mysql.jdbc.Driver
private String driver=null;
//數據庫連接url jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8","root","root
private String url=null;
//初始化數目
private int init_count=3;
//最大連接數
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++){
//記錄當前連接數
current_count++;
//把鏈接放入連接池
connections.addLast(createConnection());
}
}
//2荐糜、建新連接的方法
private Connection createConnection(){
try {
Class.forName(driver);
//原始的目標對象
final Connection conn= DriverManager.getConnection(url,username,password);
/*******創(chuàng)建代理對象********/
//創(chuàng)建代理對象
Connection proxyConnection=(Connection)Proxy.newProxyInstance(
//類加載器
conn.getClass().getClassLoader(),
//目標接口對象
new Class[] {Connection.class},
//當調用conn對象的時候自動觸發(fā)事務處理器
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//方法返回值
Object result=null;
//當前執(zhí)行的方法名
String methoName=method.getName();
//判斷執(zhí)行close()就把連接放入連接池
if ("close".equals(methoName)) {
//連接放入連接池
if(connections.size()<init_count){
connections.addLast(conn);
}else{
//如果連接池滿了就關了連接
try {
current_count--;
conn.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}else{
//調用目標方法對象
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();
}
//判斷連接池有沒有連接,如果沒有達到最大連接答渔,就創(chuàng)建
if (current_count<max_count) {
//記錄當前連接使用數
current_count++;
//創(chuàng)建連接
return createConnection();
}
//如果已達到最大連接數就关带,就拋出異常
throw new RuntimeException("當前連接已達到最大連接數目!");
}
//4、釋放鏈接
public void releaseConnection(Connection conn) {
//判斷當前連接池數目如果少于初始化就放入池中
if(connections.size()<init_count){
connections.addLast(conn);
}else{
//如果連接池滿了就關了連接
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宋雏、測試類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)建數據庫連接池基礎數據源的對象
static BasicDataSource pool=new BasicDataSource();
//設置基礎數據
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);
}
//返回連接池對象
public static DataSource getDataSource() {
return pool;
}
//測試主方法
public static void main(String[] args) {
//獲取數據庫連接
Connection connection=getDataSource().getConnection();
//查詢執(zhí)行器
Statement s=null;
//返回結果集
ResultSet rs=null;
//控制臺輸出獲取到連接的地址
System.out.println(connection);
try {
//執(zhí)行查詢
s=connection.createStatement();
rs=s.executeQuery("select * from a");
while (rs.next()) {
System.out.println(rs.getInt("a"));
}
//關閉結果集
rs.close();
//關閉執(zhí)行器
s.close();
//這里關閉連接是吧連接放回連接池
connection.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("總共的連接數目"+pool.getCurrent_count());
System.out.println("連接池里空閑的連接"+pool.getConnections().size());
}
}
三芜飘、運行結果
運行結果