代理模式之連接池的設計

一、數據源的設計-->MyDataSource

     

class MyDataSource{
    private static String url = "jdbc:mysql:///daxia";
    private static String user = "root";
    private static String password = "root";
	//初始化連接數
	private static int initCount = 3;
	//最大連接數
	private static int maxCount = 5;
	//當前連接數
	int currentCount = 0;
	//對於操作對象的性能較ArrayList好
	LinkedList<Connection> connectionsPool = new LinkedList<Connection>();
	public MyDataSource() {
		try {
			for (int i = 0; i < initCount; i++) {
			//把初始化的連接對象存放到鏈表裏面
			this.connectionsPool.addLast(this.createConnection());
			this.currentCount++;
			}
		} catch (SQLException e) {
			throw new ExceptionInInitializerError(e);
		}
	}

	public Connection getConnection() throws SQLException {
		synchronized (connectionsPool) {
			if (this.connectionsPool.size() > 0)
			//從鏈表裏面刪除頭一個連接對象,並返回該連接對象
			return this.connectionsPool.removeFirst();
			if (this.currentCount < maxCount) {
				this.currentCount++;
				return this.createConnection();
			}
			throw new SQLException("已沒有鏈接");
		}
	}

	public void free(Connection conn) {
		//釋放連接,把當前連接加到鏈表尾,並沒有真正關閉
		this.connectionsPool.addLast(conn);
	}

	//父類引用指向子類對象
	private Connection createConnection() throws SQLException {
		 Connection realConn = DriverManager.getConnection(url, user, password);
		 return new MyConnection(realConn, this);
	}

}

 

 

二、代理連接類設計-->MyConnection

 

public class MyConnection implements Connection {
                 //真正的連接對象
	private Connection realConnection;  //組合
           //數據源
	private MyDataSource  dataSource;
                 //連接使用的最大次數,超過這個次數,將真正關閉這個連接
	private int maxUseCount = 5;
	private int currentUserCount = 0;
	MyConnection(Connection connection, MyDataSource dataSource) {
		this.realConnection = connection;
		this.dataSource = dataSource;
	}
	public void clearWarnings() throws SQLException {
		this.realConnection.clearWarnings();
	}
                 //我們關心的方法
	public void close() throws SQLException {
		this.currentUserCount++;
		if (this.currentUserCount < this.maxUseCount)
		//把代理Connection放進去,不要把真正的連接放回,這樣這個方法纔有效	
                                  this.dataSource.connectionsPool.addLast(this);
		else {
			this.realConnection.close();
			this.dataSource.currentCount--;
		}
	}

	public void commit() throws SQLException {
		this.realConnection.commit();   
	}

	public Statement createStatement() throws SQLException {
		return this.realConnection.createStatement();
	}
        //其他方法略.........
}

  

 

三、jdbc工具類設計-->JdbcUtils

public final class JdbcUtils {
	private static MyDataSource myDataSource = null;
	private JdbcUtils() {
	}
	static {
		try {
			Class.forName("com.mysql.jdbc.Driver");// 只執行一次
                                 //加載了驅動後才能實例化
			myDataSource = new MyDataSource();
		} catch (ClassNotFoundException e) {
			throw new ExceptionInInitializerError(e);
		}
	}

	public static Connection getConnection() throws SQLException {
		return myDataSource.getConnection();
	}

	public static void free(Connection conn) {
			try {
				conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
		}
	}
}

 

四、 客戶端測試類-->TestConnection

public class TestConnection{
	public static void main(String[] args) {
		
		try {
			for(int i=0;i<20;i++){
			Connection conn = JdbcUtils.getConnection();
			System.out.println(conn);
			JdbcUtils.free(conn);
			}
		} catch (SQLException e) {
		e.printStackTrace();			   	   
		}

	}
}

 五、總結

     MyDataSource類實例化後,會創建多個連接對象,並把這個對象存放到連接池(connectionsPool)裏面去,方便以後的調用。由於創建連接對象比創建一般的對象的成本要高很多。所以MyDataSource類在程序中只實例化一次,即單例.

 

     MyConnection 實現了java.sql.Connection類,Connection能做的MyConnection都能做.但我們關心的只有Connection接口的close方法.其他方法的實現真正的連接類realConnection去做.

 

MyDataSource與MyConnection 相對於客戶端是透明的,客戶端使用Connection接口引用MyConnection 對象!

發佈了15 篇原創文章 · 獲贊 3 · 訪問量 2102
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章