自定义JDBC连接池及常用连接池介绍

来源:互联网 发布:easing.js 图片轮播 编辑:程序博客网 时间:2024/06/15 19:37

如果不采用连接池技术, 将导致不断创建和销毁数据库Connection, 造成性能上的损耗. 而数据库连接池技术将在池中创建一定数量的Connection, 当需要Connection时就从池中取出一个, 用完之后归还给连接池, 而不是将其销毁.

自定义数据库连接池的具体步骤分析:

a. 定义MyDataSource类, 实现DataSource接口, 并提供接口中定义的方法. 其中, 核心方法为Connection getConnection().

b. 可以在静态代码块或构造函数中创建多个Connection对象, 并将他们存储在LinkedList中. 当调用MyDataSource对象的getConnection()方法时, 从集合中取出一个Connection返回给调用者. 当调用者使用完Connection并调用Connection对象的close()方法时, 将该Connection对象归还给连接池.

c. 调用Connection对象的close()方法时, 为阻止系统销毁该连接, 而改为将连接归还给连接池, 可以采用包装设计模式. 此时包装的目标类为Connection, 因此需要定义MyConnection类并实现Connection接口. MyConnection类应该存在2个成员: Connection对象和LinkedList<Connection>对象, 这2个成员可以通过构造函数存入. 同时需要覆写close()方法, 在close()方法中实现将Connection添加到集合中.

代码如下:

 

Java代码  收藏代码
  1. public class MyDataSource implements DataSource {  
  2.     // 存储Connection对象的集合, 该集合最好采用LinkedList实现, 因为涉及到大量的删除和添加操作.  
  3.     private List<Connection> conns = new LinkedList<Connection>();  
  4.   
  5.     public MyDataSource(String propertiesFileName) throws IOException,  
  6.             ClassNotFoundException, SQLException {  
  7.         // 连接池中Connection对象的数量  
  8.         int initialSize = 10;  
  9.         // 根据配置文件的名称获得InputStream对象  
  10.         InputStream in = MyDataSource.class.getClassLoader()  
  11.                 .getResourceAsStream(propertiesFileName);  
  12.         // 使用Properties读取配置文件  
  13.         Properties prop = new Properties();  
  14.         prop.load(in);  
  15.         String url = prop.getProperty("url");  
  16.         String user = prop.getProperty("user");  
  17.         String password = prop.getProperty("password");  
  18.         String driver = prop.getProperty("driver");  
  19.   
  20.         // 加载数据库驱动  
  21.         Class.forName(driver);  
  22.         // 根据配置文件中的信息获取数据库连接  
  23.         for (int i = 0; i < initialSize; i++) {  
  24.             Connection conn = DriverManager.getConnection(url, user, password);  
  25.             conns.add(conn);  
  26.         }  
  27.     }  
  28.   
  29.     @Override  
  30.     public Connection getConnection() throws SQLException {  
  31.         // 获取从集合中移除的Connection对象, 并将其包装为MyConnection对象后返回.  
  32.         Connection conn = conns.remove(0);  
  33.         // 测试代码  
  34.         System.out.println("获取连接之后, 连接池中的Connection对象的数量为: " + conns.size());  
  35.         return new MyConnection(conn, conns);  
  36.     }  
  37.   
  38.     private class MyConnection implements Connection {  
  39.         private Connection conn;  
  40.         private List<Connection> conns;  
  41.   
  42.         public MyConnection(Connection conn, List<Connection> conns) {  
  43.             this.conn = conn;  
  44.             this.conns = conns;  
  45.         }  
  46.   
  47.         // 重写close()方法, 实现调用该方法时将连接归还给连接池  
  48.         @Override  
  49.         public void close() throws SQLException {  
  50.             conns.add(conn);  
  51.             // 测试代码  
  52.             System.out.println("将连接归还给连接池后, 连接池中的Connection对象的数量为: " + conns.size());  
  53.         }  
  54.   
  55.         // 对于其他方法, 直接调用conn对象的相应方法即可  
  56.         @Override  
  57.         public void clearWarnings() throws SQLException {  
  58.             conn.clearWarnings();  
  59.         }  
  60.   
  61.         @Override  
  62.         public void commit() throws SQLException {  
  63.             conn.commit();  
  64.         }  
  65.   
  66.         // 省略了其余Connection接口中定义的方法...  
  67.   
  68.     }  
  69.   
  70.     // 省略了其他DataSource接口中定义的方法...  
  71. }  

以下是测试代码:

Java代码  收藏代码
  1. // create table person(id int primary key auto_increment, name varchar(40), age int);  
  2. public class JDBCPool {  
  3.     @Test  
  4.     public void myDataSourceTest() {  
  5.         Connection conn = null;  
  6.         PreparedStatement st = null;  
  7.         ResultSet rs = null;  
  8.         try {  
  9.             MyDataSource pool = new MyDataSource("db.properties");  
  10.             conn = pool.getConnection();  
  11.             String sql = "insert into person(name, age) values('min', 22)";  
  12.             st = conn.prepareStatement(sql);  
  13.             st.executeUpdate();  
  14.   
  15.             sql = "select * from person";  
  16.             st = conn.prepareStatement(sql);  
  17.             rs = st.executeQuery();  
  18.             if (rs.next()) {  
  19.                 System.out.println("id = " + rs.getInt("id") + ", name = "  
  20.                         + rs.getString("name") + ", age = " + rs.getInt("age"));  
  21.             }  
  22.         } catch (Exception e) {  
  23.             e.printStackTrace();  
  24.         } finally {  
  25.             // 在release方法内会调用conn对象的close()方法  
  26.             release(null, st, conn);  
  27.         }  
  28.     }  
  29.   
  30.     // 释放资源  
  31.     public void release(ResultSet rs, Statement st, Connection conn) {  
  32.         try {  
  33.             if (rs != null) {  
  34.                 rs.close();  
  35.             }  
  36.         } catch (Exception e) {  
  37.             e.printStackTrace();  
  38.             rs = null;  
  39.         } finally {  
  40.             try {  
  41.                 if (st != null) {  
  42.                     st.close();  
  43.                 }  
  44.             } catch (SQLException e) {  
  45.                 e.printStackTrace();  
  46.                 st = null;  
  47.             } finally {  
  48.                 try {  
  49.                     if (conn != null) {  
  50.                         conn.close();  
  51.                     }  
  52.                 } catch (SQLException e) {  
  53.                     e.printStackTrace();  
  54.                     conn = null;  
  55.                 }  
  56.             }  
  57.         }  
  58.     }  
  59. }  

 

程序的输出为:

 

获取连接之后, 连接池中的Connection对象的数量为: 9

id = 6, name = min, age = 22

id = 7, name = coolxing, age = 24

将连接归还给连接池后, 连接池中的Connection对象的数量为: 10

可见这个自定义的连接池是可以工作的.

 

自定义数据库连接池只是为了学习JDBC连接池的原理, 平时项目使用的时候, 还是应该以开源的数据库连接池为主. 

常用的数据库连接池为DBCP, C3P0, 以及TOMCAT内置的连接池. 下面简单的介绍以下前两者的使用.

 

1. DBCP连接池使用步骤:

a. 导入Commons-dbcp.jar和Commons-pool.jar到project中.

b. 获取数据源DataSource对象. 可以直接创建BasicDataSource对象后调用相应的set方法, 如:

DataSource pool = new BasicDataSource();

pool.setUrl("jdbc:mysql://localhost:3306/exercise");

pool.setUsername("root");

pool.setPassword("root");

pool.setDriverClassName("com.mysql.jdbc.Driver");

pool.setInitialSize(10);

也可以通过工厂类加载配置文件获得DataSource对象, 如:

Properties prop = new Properties();

InputStream in = JDBCPool.class.getClassLoader().getResourceAsStream("dbcp.properties");

prop.load(in);

DataSource pool = BasicDataSourceFactory.createDataSource(prop);

c. 调用DataSource对象的getConnection()方法获得连接.

 

2. C3P0连接池的使用步骤:

a. 导入c3p0-0.9.1.2.jar和c3p0-0.9.1.2-jdk1.3.jar.

b. 获取数据源DataSource对象. 可以直接创建ComboPooledDataSource对象后调用相应的set方法, 如:

ComboPooledDataSource pool = new ComboPooledDataSource();

pool.setJdbcUrl("jdbc:mysql://localhost:3306/exercise");

pool.setUser("root");

pool.setPassword("root");

pool.setDriverClass("com.mysql.jdbc.Driver");

pool.setInitialPoolSize(10);

也可以在创建ComboPooledDataSource对象时传入配置节点的名称, 此时需要存在c3p0-config.xml文件. 如:

// 创建连接池, 并从c3p0-config.xml文件中的name属性为mysql的named-config元素中读取参数

ComboPooledDataSource pool = new ComboPooledDataSource("mysql");

c. 调用DataSource对象的getConnection()方法获得连接.

 

原创粉丝点击