`
senton
  • 浏览: 205861 次
  • 性别: 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模式的更加简洁了。
 

分享到:
评论

相关推荐

    一种简单JDBC数据库连接池的实现.rar_connection pool jdbc_site:www.pudn.com_数据库

    在Java编程中,数据库连接池是一种管理数据库连接的机制,它允许程序重复使用...对于初学者而言,理解并动手实现一个简单的连接池有助于深入理解数据库连接池的工作原理,为进一步学习和使用更复杂的连接池库打下基础。

    自己动手模仿Hibernate写数据库框架

    【标题】"自己动手模仿Hibernate写数据库框架"揭示了本次讨论的核心内容——尝试构建一个类似于Hibernate的数据库操作框架。Hibernate是一个流行的Java ORM(对象关系映射)框架,它简化了数据库与Java对象之间的...

    write-jdbc-deom:纯手写数据库连接池,创建多个线程的替换机制

    【标题】"write-jdbc-deom"项目是一个实践性的示例,它展示了如何从零开始构建一个简单的数据库连接池,特别是在Java环境...这个项目为你提供了一个动手实践的机会,让你能够更好地掌握数据库连接池的核心概念和技术。

    仅供学习使用,数据库连接软件文档。

    2. 连接池管理:为了提高效率和资源利用率,通常会使用连接池来管理数据库连接。连接池预先创建一定数量的连接,当应用程序需要时,可以从池中获取,使用完毕后归还。 3. SQL语言:学习基础的SQL语句,如SELECT用于...

    数据库网上书店+java实现+连接数据库

    2. 数据库连接:为了存储和管理书籍信息、用户数据、订单详情等,我们需要一个可靠的数据库系统。MySQL和SQL Server都是流行的数据库管理系统,各有优势。MySQL以其开源、高性能和易用性受到青睐,而SQL Server则在...

    图书+光盘文件

    《自己动手写网络爬虫》是一本专注于网络爬虫技术的图书,旨在帮助读者深入理解爬虫的工作原理并掌握实际编写爬虫的技能。书中的光盘文件包含了各个章节的详细内容,使得学习过程更加全面且高效。标签“爬虫”明确了...

    Accp8.0\S2\使用Java实现数据库编程 第二章

    2. 数据库连接池:了解如何使用Apache的DBCP或C3P0等开源库实现数据库连接池,提高应用程序的性能和资源利用率。 3. SQL语言:复习基本的SQL操作,包括SELECT、INSERT、UPDATE和DELETE语句,以及如何创建、修改和...

    java 连接数据库实现用户登录功能

    在实际应用中,通常会使用连接池来管理数据库连接,以提高性能和效率。同时,密码应该加密存储,而不是明文保存在数据库中,这里是为了简化示例。另外,用户界面(UI)部分,即“登录界面”,通常由前端技术如HTML、...

    使用C#调用PI-SDK进行基于PI的开发(二)——使用PI-SDK建立与PI数据库的连接

    此外,应遵循良好的编程习惯,如使用连接池、及时断开连接以及合理管理资源。 通过以上知识,你应该能够开始使用C#和PI-SDK进行基于PI的开发。记住,实践是最好的老师,所以动手尝试创建自己的应用程序并与PI系统...

    自己动手写网络爬虫

    ### 自己动手写网络爬虫 #### 知识点一:网络爬虫基础概念与应用场景 - **定义**:网络爬虫(Web Crawler),又称网页蜘蛛、网络机器人,是一种按照一定的规则,自动地抓取万维网信息的程序或者脚本。 - **应用...

    jdbc创建数据库步骤

    - 高级应用中,可以考虑使用连接池(如Apache Commons DBCP、C3P0或HikariCP)来管理数据库连接。 以上就是使用JDBC创建数据库的基本步骤。理解并熟练掌握这些步骤,有助于你在实际开发中更高效地进行数据库操作。...

    Accp8.0\S2\使用Java实现数据库编程 第五章

    其次,本章可能涵盖了连接池的概念,如Apache Commons DBCP或C3P0,它们能够有效地管理和复用数据库连接,提高应用性能,尤其是在高并发环境下。理解连接池的工作原理和配置方式,能够帮助开发者优化数据库资源的...

    JDBC直连数据库的一般方法

    9. **连接池**:在实际应用中,为了提高性能和减少资源消耗,我们通常会使用连接池(如C3P0、HikariCP等),它们可以复用已建立的数据库连接,避免频繁创建和关闭连接。 10. **批处理**:JDBC还支持批处理,允许一...

    JSP 经典范例 数据库部分

    4. 数据库连接池:在实际应用中,为了提高性能和资源管理,通常会使用数据库连接池,如C3P0、Apache DBCP或HikariCP等。连接池可以预先配置好一定数量的数据库连接,避免了频繁创建和关闭连接的开销。 5. JSP中的...

    JDBC与Java数据库程序设计

    **六、数据库连接池** 1. **连接池原理**:预先创建并管理一定数量的数据库连接,应用程序需要时从池中获取,用完归还。 2. **常见连接池**:如C3P0、DBCP、Druid、HikariCP等,它们提供更高效的连接管理和资源利用...

    Visual C#.NET数据库开发经典案例解析》的配套光盘

    10. 性能优化:包括合理的索引设计、查询优化、存储过程使用、批处理操作以及数据库连接池的利用,都是提升系统性能的关键。 通过《Visual C#.NET数据库开发经典案例解析》的学习,读者不仅可以掌握C#编程和数据库...

    计算机四级等级考试数据库真题

    最后,数据库应用开发部分可能涵盖如何使用面向对象编程语言(如Java、C#)与数据库交互,理解JDBC或ODBC接口,以及如何使用数据库连接池和缓存技术提高应用程序性能。 在复习这些真题时,不仅要关注正确答案,更要...

    企业级DB2数据库学习与认证

    总的来说,"企业级DB2数据库学习与认证"不仅涉及DB2的基础知识,还包括其在复杂企业环境中的应用和管理,以及如何通过IBM的认证考试来验证和提升自己的专业技能。对于想要在数据库领域深耕的人来说,这是一个非常有...

    VC 数据库编程三部教学

    此外,教学还会涉及一些高级话题,如存储过程、触发器的使用,以及如何在VC++中实现数据库连接池,提高系统性能。对于大型项目,数据库设计和优化也是关键,教学会提供一些设计原则和性能调优的策略。 最后,实践是...

    D10 Delphi 10.1 Berlin FireDAC 数据库开发手册

    4. **连接管理**:如何建立数据库连接,管理连接池,处理连接断开和重新连接的情况。 5. **数据操作**:阐述如何执行SQL查询,插入、更新和删除数据,以及如何使用事务确保数据的一致性。 6. **数据绑定**:介绍...

Global site tag (gtag.js) - Google Analytics