在昨天的練習中每一次練習都需要與資料庫建立連接,完成時斷開連接,然而當處理的資料量特別的時候,就很耗時時間、降低效率,今天我們學習使用連接池,將連接放在連接池中,需要使用的時候從中取出,使用完畢放回池中並不是斷開連接。
資料庫連接池的基本想法就是為資料庫連接建立一個「緩衝池」。預先在緩衝池中放入一定數量的連接,當需要建立資料庫連接時,只需從「緩衝池」中取出一個,使用完畢之後再放回去。
資料庫連線池在初始化時將建立一定數量的資料庫連線放到連線池中,這些資料庫連線的數量是由最小資料庫連線數來設定的。無論這些資料庫連線是否被使用,連線池都將一直保證至少擁有這麼多的連線數量。連接池的最大資料庫連線數量限定了這個連線池能佔有的最大連線數,當應用程式向連線池請求的連線數超過最大連線數量時,這些請求將會加入到等待佇列中。
為解決傳統開發中的資料庫連線問題,可採用資料庫連線池技術。
資料庫連接池負責分配、管理和釋放資料庫連接,它允許應用程式重複使用一個現有的資料庫連接,而不是重新建立一個。
首先我們使用DBCP連接池(一個免費開源的連接池),我們需要先將commons-dbcp-1.4.jar檔案放置目前工程下,並設定環境(新增至Build Path)。以下透過一個程式了解如何使用DBCP連接池:
我們在這裡和之前一樣需要建立一個「dbcp.properties」文件,將必要的參數放入其中,其內容如下,(此文件放在目前工程下),DBCP連線池使用這個檔案可以完成mysql、oracle的連線池的建立,但每次只能建立一個,另一個需要註解。
driverClassName = com.mysql.jdbc.Driver
url = jdbc:mysql://127.0.0.1:3306/company
username =
initialSize = 5 maxActive = 50#driverClassName = oracle.jdbc.driver.OracleDriver.url =n. = scott
maxIdle = 10
#password = tigerpackage com.atguigu.jdbc; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.sql.Connection; import java.sql.SQLException; import java.util.Properties; import javax.sql.DataSource; import org.apache.commons.dbcp.BasicDataSource; import org.apache.commons.dbcp.BasicDataSourceFactory; import org.junit.Test; public class DBCPTest { @Test public void test2() throws Exception { Properties properties = new Properties(); properties.load(new FileInputStream("dbcp.properties")); DataSource dataSource = BasicDataSourceFactory.createDataSource(properties); System.out.println("inital:" + ((BasicDataSource)dataSource).getInitialSize()); System.out.println("getMaxActive:" + ((BasicDataSource)dataSource).getMaxActive()); System.out.println("getMaxIdle:" + ((BasicDataSource)dataSource).getMaxIdle()); Connection connection = dataSource.getConnection(); System.out.println(connection); connection.close(); } }
C3P0池
池C3P0個連接池
池
C3P0個連接池
池
C3P0個連接池
池需要先將commons-dbcp-1.4.jar檔案放置目前工程下,並設定環境(新增至Build Path)。
這裡透過一個程式來了解如何使用DBCP連接池:如同DBCP連接池,我們需要建立一個「c3p0-config.xml」文件,將必要的參數放入其中,其內容如下,(此文件放置在當工程的src目錄)
🎜🎜🎜🎜🎜🎜🎜410e9fdc4dfed7c6bf6579b026d5784d
c51687d1a05d78a9c8bfbf9e7c74eb820d6c32e92ae989fc34d9e00b7bc32b5acom.mysql.jdbc.Driverdde4123f2ed5a21d0bae333af89830f9cf7527e3d84e835db325c5614ed272eejdbc:mysql://127.0.0.1:3306/schooldde4123f2ed5a21d0bae333af89830f9f7373e25e87d494693d434429b7ce642rootdde4123f2ed5a21d0bae333af89830f9ee828f7b579ab9fcb520bd2707eb425f123456dde4123f2ed5a21d0bae333af89830f997693d639e0067a4db3de784c5c67a405dde4123f2ed5a21d0bae333af89830f9fcb4c8c9635d4481996c28519c5e3a065dde4123f2ed5a21d0bae333af89830f9f8b9c1fa45b70539ab4b242d549b921d5dde4123f2ed5a21d0bae333af89830f92a833e8e9752629d2edd3c4c76fc437950dde4123f2ed5a21d0bae333af89830f90ea635411359c6d8b4b061ea2d91e1d90dde4123f2ed5a21d0bae333af89830f9ebb4d20ac968f7136ede8a953b3318815dde4123f2ed5a21d0bae333af89830f9aec5776c7f3aacabd9df06bc1412f08fc980b48734bacc1c8c19987d562b9b050d6c32e92ae989fc34d9e00b7bc32b5aoracle.jdbc.driver.OracleDriverdde4123f2ed5a21d0bae333af89830f9cf7527e3d84e835db325c5614ed272eejdbc:mysql://127.0.0.1:3306/schooldde4123f2ed5a21d0bae333af89830f9f7373e25e87d494693d434429b7ce642rootdde4123f2ed5a21d0bae333af89830f9ee828f7b579ab9fcb520bd2707eb425f123456dde4123f2ed5a21d0bae333af89830f9aec5776c7f3aacabd9df06bc1412f08f
e2c7bc088748bdf90a420dcdf517c408
DBCP连接池使用这个文件可以完成mysql、oracle的连接池的建立,每次只能建立一个,但是另一个需要注释起来。因为我们是根据c51687d1a05d78a9c8bfbf9e7c74eb82 名建立连接,
package com.atguigu.jdbc; import java.beans.PropertyVetoException; import java.sql.Connection; import java.sql.SQLException; import javax.sql.DataSource; import org.junit.Test; import com.mchange.v2.c3p0.*; public class C3P0Test { @Test public void test1() throws PropertyVetoException, SQLException { DataSource dataSource = new ComboPooledDataSource("mysql-config"); // 它会默认自动去读取文件 System.out.println(dataSource); Connection connection = dataSource.getConnection(); System.out.println(connection); connection.close();// 把连接归还给连接池 DataSources.destroy(dataSource);// 完全释放池中所有连接,并销毁连接池!! } @Test public void test2() throws PropertyVetoException, SQLException { DataSource dataSource = new ComboPooledDataSource("oracle-config"); // 它会默认自动去读取文件 System.out.println(dataSource); Connection connection = dataSource.getConnection(); System.out.println(connection); connection.close();// 把连接归还给连接池 DataSources.destroy(dataSource);// 完全释放池中所有连接,并销毁连接池!! } }
学习了连接池之后,JdbcUtil工具类中的getConnection方法就可以应用,如下:
package com.atguigu.jdbc; import java.io.FileInputStream; import java.io.IOException; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.Properties; import javax.sql.DataSource; import com.mchange.v2.c3p0.ComboPooledDataSource; import com.mchange.v2.c3p0.DataSources; /** * 预备工作 : * 1) 把要访问的数据库相关的驱动程序复制到项目中, 就是jar包 * 2) 配置项目属性, 把jar包导入到本项目的buildpath中 * @author Administrator * */ public class JdbcUtil { private static DataSource dataSource; // 声明静态属性对象引用. static { dataSource = new ComboPooledDataSource("mysql-config"); // 连接池对象只需要创建一次就可以了 } public static Connection getConnection() throws SQLException { return dataSource.getConnection(); // 要想获取连接, 只需要从连接池中获取,用完以后, 再归还回来 } public static Connection getConnectionOld() throws IOException, ClassNotFoundException, SQLException { // 1) 读取配置文件 Properties properties = new Properties(); properties.load(new FileInputStream("jdbc.properties")); // 2) 获取配置文件中的必要的信息 String driverClass = properties.getProperty("driverClass"); String url = properties.getProperty("url"); String user = properties.getProperty("user"); String password = properties.getProperty("password"); // 3) 注册驱动 , 加载驱动类 Class.forName(driverClass); // 4) 通过驱动管理器获取连接(需要url,用户,密码) return DriverManager.getConnection(url, user, password);// 暗含 new Socket(host,port), 认证,其他各种初始化操作 } //关闭连接 public static void close(Connection connection) { close(connection, null); } public static void close(Connection connection, Statement statement) { close(connection, statement, null); } public static void close(Connection connection, Statement statement, ResultSet resultSet) { if (resultSet != null) { try { resultSet.close(); } catch (Exception e) { e.printStackTrace(); } } if (statement != null) { try { statement.close(); } catch (Exception e) { e.printStackTrace(); } } if (connection != null) { try { connection.close(); } catch (Exception e) { e.printStackTrace(); } } } //销毁连接池 public static void destroy() { try { DataSources.destroy(dataSource); } catch (SQLException e) { e.printStackTrace(); } } }
将常用的操作数据库的JDBC的类和方法集合在一起,就是DBUtils.JDBC。提供供我们使用的工具类QueryRunner来执行操作。
在使用之前我们仍然需要将commons-dbutils-1.3.jar添加到当前工程下,并添加到path路径。
package com.atguigu.jdbc; import java.sql.Connection; import java.sql.SQLException; import java.util.List; import org.apache.commons.dbutils.QueryRunner; import org.apache.commons.dbutils.handlers.ArrayListHandler; import org.apache.commons.dbutils.handlers.BeanHandler; import org.apache.commons.dbutils.handlers.BeanListHandler; import org.apache.commons.dbutils.handlers.ScalarHandler; import org.junit.Test; public class QueryRunnerTest { // 使用我们自定义工具实现表的创建 @Test public void test1() throws SQLException { QueryRunner qr = new QueryRunner(); Connection connection = JdbcUtil.getConnection(); qr.update(connection, "create table test2(aa int, bb varchar(10))"); JdbcUtil.close(connection); } // 使用我们自定义工具向表中插入一条记录 @Test public void test2() throws SQLException { QueryRunner qr = new QueryRunner(); Connection connection = JdbcUtil.getConnection(); int rows = qr.update(connection, "insert into test2(aa, bb) values(?,?)", 10, "xxx"); System.out.println(rows + " rows"); JdbcUtil.close(connection); } // 使用DBUtils.JDBC接口中提供的方法对departments表进行查询,把结果集中的所有记录转换为department对象集合并存入List集合中,然后遍历输出对象 @Test public void test3() throws SQLException { //query(Connection conn, String sql, ResultSetHandler<T> rsh, Object... params) String sql = "select * from departments where department_id > ?"; QueryRunner qr = new QueryRunner(); Connection connection = JdbcUtil.getConnection(); BeanListHandler<Department> rsh = new BeanListHandler<Department>(Department.class); // 把结果集中的所有记录转换为对象集合 List<Department> list = qr.query(connection, sql, rsh, 20); for (Department department : list) { System.out.println(department); } } // 使用DBUtils.JDBC接口中提供的方法对departments表进行查询,把结果集中的一条记录转换为department实体对象,然后输出对象 @Test public void test4() throws SQLException { String sql = "select * from departments where department_id = ?"; QueryRunner qr = new QueryRunner(); Connection connection = JdbcUtil.getConnection(); BeanHandler<Department> rsh = new BeanHandler<Department>(Department.class); // 把结果集中的一条记录转换为实体对象 Department objDepartment = qr.query(connection, sql, rsh, 20); System.out.println(objDepartment); } // 使用DBUtils.JDBC接口中提供的方法对departments表进行查询,将每一条记录存入集合中,然后遍历输出每一个数据 @Test public void test5() throws SQLException { String sql = "select * from employees"; QueryRunner qr = new QueryRunner(); Connection connection = JdbcUtil.getConnection(); ArrayListHandler rsh = new ArrayListHandler(); List<Object[]> list = qr.query(connection, sql, rsh); for (Object[] objects : list) { for (int i = 0; i < objects.length; i++) { System.out.print(objects[i] + "\t"); } System.out.println(); } } // 使用DBUtils.JDBC接口中提供的方法对departments表进行查询,将查询到的一个数据输出 @Test public void test6 () throws SQLException { String sql = "select count(*) from world.country"; QueryRunner qr = new QueryRunner(); Connection connection = JdbcUtil.getConnection(); ScalarHandler rsh = new ScalarHandler(); Object singleValue = qr.query(connection, sql, rsh); System.out.println(singleValue); } @Test public void test7() throws Exception { QueryRunner qr = new QueryRunner(); List<Object> list = qr.query(JdbcUtil.getConnection(), "select * from student", new ColumnListHandler(1)); for (Object object : list) { System.out.println(object); } } //MapHandler把第一行数据封装到Map集合中, 列名作为键, 对应值作为值 @Test public void test8() throws Exception { QueryRunner qr = new QueryRunner(); Map<String, Object> map = qr.query(JdbcUtil.getConnection(), "select * from student", new MapHandler()); Set<String> keys = map.keySet(); for (String key : keys) { Object value = map.get(key); System.out.println(key + " -------- " + value); } } //MapListHandler把一行数据封装到Map集合中, 并把所有行生成的Map再放入一个List集合 @Test public void test9() throws Exception { QueryRunner qr = new QueryRunner(); List<Map<String, Object>> list = qr.query(JdbcUtil.getConnection(), "select * from student", new MapListHandler()); for (Map<String, Object> map2 : list) { Set<String> keys = map2.keySet(); for (String key : keys) { Object value = map2.get(key); System.out.println(key + " -------- " + value); } System.out.println(); } } }
到这里就可以统一整理一下自己定义的JdbcUtil工具类、CommonUtil工具类,使自定义的工具类能达到JDButi.JDBC相同的功能,如下:
JdbcUtils.java
package com.atguigu.jdbc; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import javax.sql.DataSource; import com.mchange.v2.c3p0.ComboPooledDataSource; import com.mchange.v2.c3p0.DataSources; public class JdbcUtil { private static DataSource dataSource; static { dataSource = new ComboPooledDataSource("config1"); // 它必须依赖文件src/c3p0-config.xml } // 获取c3p0连接池的连接 public static Connection getConnection() throws SQLException { return dataSource.getConnection(); } public static void close(Connection connection) { close(connection, null); } public static void close(Connection connection, Statement statement) { close(connection, statement, null); } public static void close(Connection connection, Statement statement, ResultSet resultSet) { if (resultSet != null) { try { resultSet.close(); } catch (Exception e) { e.printStackTrace(); } } if (statement != null) { try { statement.close(); } catch (Exception e) { e.printStackTrace(); } } if (connection != null) { try { connection.close(); } catch (Exception e) { e.printStackTrace(); } } } public static void destroy() { try { DataSources.destroy(dataSource); } catch (SQLException e) { e.printStackTrace(); } } }
CommonUtil.java
package com.atguigu.jdbc; import java.lang.reflect.Field; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; public class CommonUtil { /** * 把结果集中的每一行都放入Object对象数组中, 再把所有的Object对象数组放入一个List集合中. * @throws SQLException */ public static List<Object[]> query(Connection connection, String sql, Object... values) throws SQLException { PreparedStatement preparedStatement = null; ResultSet resultSet = null; try { preparedStatement = connection.prepareStatement(sql); fillArguments(preparedStatement, values); resultSet = preparedStatement.executeQuery(); List<Object[]> list = new ArrayList<Object[]>(); int cols = resultSet.getMetaData().getColumnCount(); while (resultSet.next()) { Object[] dataRow = new Object[cols]; for (int i = 0; i < dataRow.length; i++) { dataRow[i] = resultSet.getObject(i + 1); } list.add(dataRow); } return list; } finally { JdbcUtil.close(null, preparedStatement, resultSet); } } /** * 把结果集中的第一行数据,全放入一个对象数组中 * @throws SQLException */ public static Object[] queryValueArray(Connection connection, String sql, Object... values) throws SQLException { PreparedStatement preparedStatement = null; ResultSet resultSet = null; try { preparedStatement = connection.prepareStatement(sql); fillArguments(preparedStatement, values); resultSet = preparedStatement.executeQuery(); if (resultSet.next()) { Object[] dataRow = new Object[resultSet.getMetaData().getColumnCount()]; for (int i = 0; i < dataRow.length; i++) { dataRow[i] = resultSet.getObject(i + 1); } return dataRow; } else { return null; } } finally { JdbcUtil.close(null, preparedStatement, resultSet); } } /** * 从结果集中获取第一行的第一列 * @throws SQLException */ public static Object queryValue(Connection connection, String sql, Object... values) throws SQLException { PreparedStatement preparedStatement = null; ResultSet resultSet = null; try { preparedStatement = connection.prepareStatement(sql); fillArguments(preparedStatement, values); resultSet = preparedStatement.executeQuery(); if (resultSet.next()) { return resultSet.getObject(1); } else { return null; } } finally { JdbcUtil.close(null, preparedStatement, resultSet); } } /** * 把结果集中第一行转换为对象返回 * @throws SQLException * @throws SecurityException * @throws NoSuchFieldException * @throws IllegalAccessException * @throws InstantiationException */ public static <T> T queryBean(Connection connection, String sql, Class<T> clazz, Object... values) throws SQLException, NoSuchFieldException, SecurityException, InstantiationException, IllegalAccessException { PreparedStatement preparedStatement = null; ResultSet resultSet = null; try { preparedStatement = connection.prepareStatement(sql); fillArguments(preparedStatement, values); resultSet = preparedStatement.executeQuery(); if (resultSet.next()) { T t = clazz.newInstance(); ResultSetMetaData metaData = resultSet.getMetaData(); int cols = metaData.getColumnCount(); for (int i = 0; i < cols; i++) { String label = metaData.getColumnLabel(i + 1); Object value = resultSet.getObject(label); Field field = clazz.getDeclaredField(label); field.setAccessible(true); field.set(t, value); } return t; } else { return null; } } finally { JdbcUtil.close(null, preparedStatement, resultSet); } } /** * 把结果集的所有记录都封装成对象,并把所有对象放在一个List集合中 * @throws SQLException * @throws IllegalAccessException * @throws InstantiationException * @throws SecurityException * @throws NoSuchFieldException */ public static <T> List<T> query(Connection connection, String sql, Class<T> clazz, Object... values) throws SQLException, InstantiationException, IllegalAccessException, NoSuchFieldException, SecurityException { PreparedStatement preparedStatement = null; ResultSet resultSet = null; try { preparedStatement = connection.prepareStatement(sql); fillArguments(preparedStatement, values); resultSet = preparedStatement.executeQuery(); List<T> list = new ArrayList<T>(); ResultSetMetaData metaData = resultSet.getMetaData(); int cols = metaData.getColumnCount(); while (resultSet.next()) { T t = clazz.newInstance(); for (int i = 0; i < cols; i++) { String label = metaData.getColumnLabel(i + 1); Object value = resultSet.getObject(label); if (value != null) { Field field = clazz.getDeclaredField(label); field.setAccessible(true); field.set(t, value); } } list.add(t); } return list; } finally { JdbcUtil.close(null, preparedStatement, resultSet); } } /** * 通用更新操作 * @throws SQLException */ public static int update(Connection connection, String sql, Object... values) throws SQLException { PreparedStatement preparedStatement = null; try { preparedStatement = connection.prepareStatement(sql); fillArguments(preparedStatement, values); return preparedStatement.executeUpdate(); } finally { JdbcUtil.close(null, preparedStatement); } } public static void fillArguments(PreparedStatement preparedStatement, Object... values) throws SQLException { for (int i = 0; i < values.length; i++) { preparedStatement.setObject(i + 1, values[i]); } } }
综合之前学习过的知识,在这里创建一个BaseDAO8742468051c85b06f0a0af9e3e506b5c类借助DBUtils工具类实现数据操作功能:
package com.atguigu.jdbc; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.sql.Connection; import java.sql.SQLException; import java.util.List; import org.apache.commons.dbutils.QueryRunner; import org.apache.commons.dbutils.handlers.BeanHandler; import org.apache.commons.dbutils.handlers.BeanListHandler; import org.apache.commons.dbutils.handlers.ScalarHandler; public class BaseDAO<T>{ protected Class<T> clazz; // T泛型究竟是什么类型, 用类模板对象来描述 protected QueryRunner qr = new QueryRunner(); // 用于执行通用查询和更新的工具类对象 protected Connection connection; // 数据库连接 protected String tableName; // 涉及到的表,需要通过构造器初始化赋值 public JdbcDAO(String tableName) { // 以下代码的执行者是子类对象,所以this.getClass是获取子类的类模板对象 Type type = this.getClass().getGenericSuperclass(); // JdbcDAO<Teacher> if (type instanceof ParameterizedType) { ParameterizedType parameterizedType = (ParameterizedType)type;//JdbcDAO<Teacher> Type[] types = parameterizedType.getActualTypeArguments(); clazz = (Class<T>)types[0]; } else { clazz = (Class<T>)Object.class; } // 获取一个连接供所有方法使用 try { connection = JdbcUtil.getConnection(); } catch (SQLException e) { e.printStackTrace(); } this.tableName = tableName; } //获得记录中具体的一个数据 public Object getValue(String sql, Object... values) { try { return qr.query(connection, sql, new ScalarHandler(), values); } catch (SQLException e) { e.printStackTrace(); } return null; } //获得一行数据并封装成javabean对象 public T get(String sql, Object... values) { try { return qr.query(connection, sql, new BeanHandler<T>(clazz), values); } catch (SQLException e) { e.printStackTrace(); } return null; } //获得多行记录,封装成javabean对象,保存在list集合中 public List<T> getList(String sql, Object... values) { try { return qr.query(connection, sql, new BeanListHandler<T>(clazz), values); } catch (SQLException e) { e.printStackTrace(); } return null; } //获得所有记录,封装成javabean对象,保存在list集合中 public List<T> getAll() { return getList("select * from " + tableName); } //根据id获取某一条记录,并封装成javabean对象返回 public T getById(int id) { return get("select * from " + tableName + " where id = ?", id); } //根据id删除某一条记录,删除成功返回ture,失败返回false public boolean deleteById(int id) { int rows = update("delete from " + tableName + " where id = ?", id); if (rows > 0) { return true; } return false; } //通用的更新操作 public int update(String sql, Object... values) { try { return qr.update(connection, sql, values); } catch (SQLException e) { e.printStackTrace(); } return 0; } //关闭连接 public void close() { JdbcUtil.close(connection); } }
以上就是JDBC-数据连接池的使用 的内容,更多相关内容请关注PHP中文网(www.php.cn)!