一、數據源的設計-->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 對象!