自定義實現資料庫連線池
資料庫連線池:
>資料庫的連線物件建立工作,比較消耗效能
>一開始先在記憶體中開闢一塊空間(集合) , 先往池子裡面放置 多個連線物件。 後面需要連線的話,直接從池子裡面去。不要去自己建立連線了。 使用完畢, 要記得歸還連線。確保連線物件能迴圈利用。即建立一個池子(容器) , 專門用來管理連線物件
連線池作用:
>更快響應速度
連線池裡的連線在一開始就已經建立好了,後面如果需要直接拿就可以了,無需建立
>資源的重複利用、避免重複建立物件
連線物件使用完畢後,再歸還到池子中進行統一管理即可
資料庫連線池MyDataSource程式碼
/* * 這是一個數據庫連線池 * 一開始先往池子裡面放10個連線 * * 1、開始建立10個連線 * 2、來的程式通過getConnection獲取連線 * 3、用完之後,使用addBack歸還連線 * 4、擴容 */ public class MyDataSource implements DataSource { List<Connection> list = new ArrayList<Connection>(); public MyDataSource() { for (int i = 0; i < 10; i++) { Connection conn = JDBCUtil.getCoon(); list.add(conn); } } //該連線池對外公佈的獲取連線的方法 @Override public Connection getConnection() throws SQLException { System.out.println(list.size()); //來拿連線的時候,先看看池子裡還有沒有 if(list.size() == 0) { for(int i = 0;i<3;i++) { Connection conn = JDBCUtil.getCoon(); list.add(conn); } } //remove(0)----->移除第一個。移除的是集合裡的第一個。 Connection conn = list.remove(0); return conn; } /* * 用完之後,記得歸還 */ public void addBack(Connection conn) { list.add(conn); } ........... }
測試程式碼為:
public class TestPool { @Test public void testPool() { Connection conn = null; PreparedStatement ps = null; MyDataSource dataSource = new MyDataSource(); try { conn = dataSource.getConnection(); String sql = "insert into account values (null,'夏虹',1000)"; ps = conn.prepareStatement(sql); ps.executeUpdate(); } catch (SQLException e) { e.printStackTrace(); } finally { try { ps.close(); } catch (SQLException e) { e.printStackTrace(); } dataSource.addBack(conn); } } }
以上程式碼的問題是:
1、物件沒有做成單例
在哪裡使用,都需要new MyDataSource(). 這就會造成有多個物件的情況出現,那就不只是一個池子了
2、需要額外記住addBack方法
sun公司定義的資料庫連線池裡面並沒有這個addBack方法,所以誰需要用我們這個連線池,需要記住這個方法是用來回收連線物件的。
3、無法面向介面程式設計。
由於我們的連線池直接定義成了一個類,並且裡面還額外添加了一個addBack方法,這就造成了我們無法面向介面程式設計。
為了解決上面出現的問題:
不打算新增 addBack 方法, 而是擴充套件原來的 close 方法。 讓 close 方法,不關閉連線,而是把連線物件歸還給池子。要想實現這個需求,有以下幾種方式:
1. 直接修改JDBC 裡面的那個 Connection 介面的具體實現。讓它的 close 方法別關閉連線,而是變成回收連線物件。
答案: 無法辦到。 咱們沒把發修改人家的原始碼
2. 既然不能直接修改,那麼我們改成自己定義一個類,然後繼承那個 Connection 介面的實現類, 然後在它的 close 方法基礎上,加入我們的回收邏輯。
答案: 無法辦到, 因為我們根本不知道 Connection 介面的實現類是哪一個.
3. 使用裝飾者模式來實現。
答案: 可以辦到。
使用裝飾者模式後的程式碼是:
定義一個類實現Connection 介面:
注意,使用了Connection介面的哪個方法
public class ConnectionWrap implements Connection{
Connection conn = null;
List<Connection> list = null;
public ConnectionWrap(Connection conn,List<Connection> list) {
super();
this.conn = conn;
this.list = list;
}
@Override
public void close() throws SQLException {
System.out.println("有人來歸還連線物件了。歸還之前,池子裡面是:" + list.size());
// conn.close();
list.add(conn);
System.out.println("有人來歸還連線物件了。歸還之後,池子裡面是:" + list.size());
}
@Override
public PreparedStatement prepareStatement(String sql) throws SQLException {
return conn.prepareStatement(sql);
}
........
}
資料庫連線池 MyDataSource程式碼為:
/*
* 這是一個數據庫連線池
* 一開始先往池子裡面放10個連線
*
* 1、開始建立10個連線
* 2、來的程式通過getConnection獲取連線
* 3、用完之後,使用addBack歸還連線
* 4、擴容
*/
public class MyDataSource implements DataSource {
List<Connection> list = new ArrayList<Connection>();
public MyDataSource() {
for (int i = 0; i < 10; i++) {
Connection conn = JDBCUtil.getCoon();
list.add(conn);
}
}
//該連線池對外公佈的獲取連線的方法
@Override
public Connection getConnection() throws SQLException {
System.out.println(list.size());
//來拿連線的時候,先看看池子裡還有沒有
if(list.size() == 0) {
for(int i = 0;i<3;i++) {
Connection conn = JDBCUtil.getCoon();
list.add(conn);
}
}
//remove(0)----->移除第一個。移除的是集合裡的第一個。
Connection conn = list.remove(0);
Connection connection = new ConnectionWrap(conn,list);
return connection;
}
..........
}
test程式碼為:
public class TestPool {
@Test
public void testPool() {
Connection conn = null;
PreparedStatement ps = null;
MyDataSource dataSource = new MyDataSource();
try {
conn = dataSource.getConnection();
String sql = "insert into account values (null,'夏虹',1000)";
ps = conn.prepareStatement(sql);
ps.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
// dataSource.addBack(conn);
JDBCUtil.release(conn, ps);
}
}
}