1. 程式人生 > >自定義實現資料庫連線池

自定義實現資料庫連線池

資料庫連線池

>資料庫的連線物件建立工作,比較消耗效能

>一開始先在記憶體中開闢一塊空間(集合) , 先往池子裡面放置 多個連線物件。  後面需要連線的話,直接從池子裡面去。不要去自己建立連線了。  使用完畢, 要記得歸還連線。確保連線物件能迴圈利用。即建立一個池子(容器) , 專門用來管理連線物件

連線池作用

>更快響應速度

連線池裡的連線在一開始就已經建立好了,後面如果需要直接拿就可以了,無需建立

>資源的重複利用、避免重複建立物件

連線物件使用完畢後,再歸還到池子中進行統一管理即可

資料庫連線池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);
		}
	}

}