一、数据源的设计-->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 对象!