`
senton
  • 浏览: 200439 次
  • 性别: Icon_minigender_1
  • 来自: 紫禁城
社区版块
存档分类
最新评论

自己动手写数据库连接池

    博客分类:
  • J2SE
阅读更多

在前面的文章中已经说过使用连接池的很多好处和优势,也曾讨论过怎么使用数据库连接池,不过那时用的都是别人写好的一些DataSource类。现在我们自己来写一个数据库连接池,下面使用两种方法来实现,这里分别用到了两种设计模式,即Decorator(包装模式)和Proxy(代理模式)(关于其他的模式在后续的学习过程中都会一一介绍,敬请关注),首先来看第一种实现方法,也就是使用Decorator设计模式:


我们在这里引入一个ConnectionDecortor类,代码如下,此方法的功能不多介绍,看名字就知道是包装了Connection接口,对此接口的方法都做了简单的实现:

import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.SQLWarning;
import java.sql.Savepoint;
import java.sql.Statement;
import java.util.Map;

public class ConnectionDecorator implements Connection {
 Connection conn;

 public ConnectionDecorator(Connection conn) {
  this.conn = conn;
 }

 public Statement createStatement() throws SQLException {
  return conn.createStatement();
 }

 public PreparedStatement prepareStatement(String arg0) throws SQLException {
  return conn.prepareStatement(arg0);
 }

 public CallableStatement prepareCall(String arg0) throws SQLException {
  return conn.prepareCall(arg0);
 }

 public String nativeSQL(String arg0) throws SQLException {
  return conn.nativeSQL(arg0);
 }

 public void setAutoCommit(boolean arg0) throws SQLException {
  conn.setAutoCommit(arg0);
 }

 public boolean getAutoCommit() throws SQLException {
  return conn.getAutoCommit();
 }

 public void commit() throws SQLException {
  conn.commit();
 }

 public void rollback() throws SQLException {
  conn.rollback();
 }

 public void close() throws SQLException {
  conn.close();
 }

 public boolean isClosed() throws SQLException {
  return conn.isClosed();
 }

 public DatabaseMetaData getMetaData() throws SQLException {
  return conn.getMetaData();
 }

 public void setReadOnly(boolean arg0) throws SQLException {
  conn.setReadOnly(arg0);
 }

 public boolean isReadOnly() throws SQLException {
  return conn.isReadOnly();
 }

 public void setCatalog(String arg0) throws SQLException {
  conn.setCatalog(arg0);
 }

 public String getCatalog() throws SQLException {
  
  return conn.getCatalog();
 }

 public void setTransactionIsolation(int arg0) throws SQLException {
  
  conn.setTransactionIsolation(arg0);
 }

 public int getTransactionIsolation() throws SQLException {
  
  return conn.getTransactionIsolation();
 }

 public SQLWarning getWarnings() throws SQLException {
  
  return conn.getWarnings();
 }

 public void clearWarnings() throws SQLException {
  
  conn.clearWarnings();
 }

 public Statement createStatement(int arg0, int arg1) throws SQLException {
  
  return conn.createStatement(arg0, arg1);
 }

 public PreparedStatement prepareStatement(String arg0, int arg1, int arg2)
   throws SQLException {
  
  return conn.prepareStatement(arg0, arg1, arg2);
 }

 public CallableStatement prepareCall(String arg0, int arg1, int arg2)
   throws SQLException {
  
  return conn.prepareCall(arg0, arg1, arg2);
 }

 public Map<String, Class<?>> getTypeMap() throws SQLException {
  
  return conn.getTypeMap();
 }

 public void setTypeMap(Map<String, Class<?>> arg0) throws SQLException {
  
  conn.setTypeMap(arg0);
 }

 public void setHoldability(int arg0) throws SQLException {
  
  conn.setHoldability(arg0);
 }

 public int getHoldability() throws SQLException {
  
  return conn.getHoldability();
 }

 public Savepoint setSavepoint() throws SQLException {
  
  return conn.setSavepoint();
 }

 public Savepoint setSavepoint(String arg0) throws SQLException {
  
  return conn.setSavepoint(arg0);
 }

 public void rollback(Savepoint arg0) throws SQLException {
  
  conn.rollback(arg0);
 }

 public void releaseSavepoint(Savepoint arg0) throws SQLException {
  
  conn.releaseSavepoint(arg0);
 }

 public Statement createStatement(int arg0, int arg1, int arg2)
   throws SQLException {
  
  return conn.createStatement(arg0, arg1, arg2);
 }

 public PreparedStatement prepareStatement(String arg0, int arg1, int arg2,
   int arg3) throws SQLException {
  
  return conn.prepareStatement(arg0, arg1, arg2, arg3);
 }

 public CallableStatement prepareCall(String arg0, int arg1, int arg2,
   int arg3) throws SQLException {
  
  return conn.prepareCall(arg0, arg1, arg2);
 }

 public PreparedStatement prepareStatement(String arg0, int arg1)
   throws SQLException {
  
  return conn.prepareStatement(arg0, arg1);
 }

 public PreparedStatement prepareStatement(String arg0, int[] arg1)
   throws SQLException {
  
  return conn.prepareStatement(arg0, arg1);
 }

 public PreparedStatement prepareStatement(String arg0, String[] arg1)
   throws SQLException {
  
  return conn.prepareStatement(arg0, arg1);
 }
}

从代码可以看出我们使用这个类只是对传入的Connection加上了一个外壳。


定义一个接口ConnectionPool,此接口只有两个方法,即getConnection()和releaseConnection():
import java.sql.Connection;
import java.sql.SQLException;

public interface ConnectionPool {
 Connection getConnection() throws SQLException;

 void releaseConnection(Connection conn);
}

下面DBConnectionPool类是对上面接口的实现:

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Vector;

public class DBConnectionPool implements ConnectionPool {
 //一个存储连接对象的集合,即上面所谓的连接池
 private static Vector<Connection> pool;
 //最多建立20个连接
 private final int POOL_MAX_SIZE = 20;
 //根据连接池中是否有连接对象来进行处理
 public synchronized Connection getConnection() throws SQLException {
  if (pool == null)
   pool = new Vector<Connection>();
  Connection conn = null;
  //如果没有连接对象则新建一个
  if (pool.isEmpty())
   conn = createConnection();
  else {
   //如果有连接对象则取一个出来返回给客户端
   int last_idx = pool.size() - 1;
   conn = pool.get(last_idx);
   pool.remove(pool.get(last_idx));
  }

  return new PooledConnection(this,conn);
 }

 public synchronized void releaseConnection(Connection conn) {
  if (conn instanceof PooledConnection && pool.size() > POOL_MAX_SIZE) {
   try {
    conn.close();
   } catch (SQLException e) {
    e.printStackTrace();
   }
  } else {
   pool.add(conn);
  }
 }

 //创建连接的方法
 private Connection createConnection() {
  try {
   Class.forName("com.mysql.jdbc.Driver");
   Connection conn = DriverManager.getConnection("jdbc:mysql:///Student", "root", "");
   return conn;
  } catch (ClassNotFoundException e) {
   e.printStackTrace();
   return null;
  } catch (SQLException e) {
   e.printStackTrace();
   return null;
  }
 }
}
下面的PooledConnection类中我们会对包装类ConnectionDecorator的close()方法做了一些特殊的处理,并不是直接关闭它,而是交给ConnectionPool 的 releaseConnection()去处理。

import java.sql.Connection;
import java.sql.SQLException;

public class PooledConnection extends ConnectionDecorator implements Connection {

 private ConnectionPool connPool;

 public PooledConnection(ConnectionPool connPool, Connection conn) {
  super(conn);
  this.connPool = connPool;
 }

 public void close() throws SQLException{
  connPool.releaseConnection(this.conn);
 }
}
至此第一种方法就实现了。下面来看第二种方法,即使用Proxy模式来实现:
ConnectionHandler 实现jdk提供的InvocationHandler 接口,重写了invoke方法。

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;

public class ConnectionHandler implements InvocationHandler {

 Connection conn;

 ConnectionPool pool;

 public ConnectionHandler(ConnectionPool pool) {
  this.pool = pool;
 }

 //bind方法是将动态代理绑定到指定的Connection。返回一个绑定代理后的Connection
 public Connection bind(Connection conn) {
  this.conn = conn;
  Connection proxyConn = (Connection) Proxy.newProxyInstance(conn
    .getClass().getClassLoader(), conn.getClass().getInterfaces(),
    this);
  return proxyConn;
 }
 //方法拦截器,判断当前调用的方法是否“close”方法,是则调用ConnectionPool的releaseConnection()方法
 //否则直接调用Connection的方法。
 public Object invoke(Object arg0, Method arg1, Object[] arg2)
   throws Throwable {
  Object object = null;
  if ("close".equals(arg1.getName())) {
   pool.releaseConnection(conn);
  } else {
   object = arg1.invoke(conn, arg2);
  }
  return object;
 }
}
然后把上面的DBConnectionPool.getConnection()方法做一点小小的修改:
 //此方法返回值为一个经过绑定的连接
 public synchronized Connection getConnection() throws SQLException {
  if (pool == null)
   pool = new Vector<Connection>();
  Connection conn = null;
  if (pool.isEmpty())
   conn = createConnection();
  else {
   int last_idx = pool.size() - 1;
   conn = pool.get(last_idx);
   pool.remove(pool.get(last_idx));
  }

  ConnectionHandler handler = new ConnectionHandler(this);
  return handler.bind(conn);
 }
可以看出,基于Proxy模式的实现相对于Decorator模式的更加简洁了。
 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics