数据库连接池&DBUtils_agg
数据库连接池
示例1
抽取工具类
package com.atguigu.util; 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; /** * JDBC 的工具类 * * 其中包含: 获取数据库连接, 关闭数据库资源等方法. */ public class JDBCTools { //处理数据库事务的 //提交事务 public static void commit(Connection connection){ if(connection != null){ try { connection.commit(); } catch (SQLException e) { e.printStackTrace(); } } } //回滚事务 public static void rollback(Connection connection){ if(connection != null){ try { connection.rollback(); } catch (SQLException e) { e.printStackTrace(); } } } //开始事务 public static void beginTx(Connection connection){ if(connection != null){ try { connection.setAutoCommit(false); } catch (SQLException e) { e.printStackTrace(); } } } private static DataSource dataSource = null; //数据库连接池应只被初始化一次. static{ dataSource = new ComboPooledDataSource("helloc3p0"); } public static Connection getConnection() throws Exception { return dataSource.getConnection(); } public static void releaseDB(ResultSet resultSet, Statement statement, Connection connection) { if (resultSet != null) { try { resultSet.close(); } catch (SQLException e) { e.printStackTrace(); } } if (statement != null) { try { statement.close(); } catch (SQLException e) { e.printStackTrace(); } } if (connection != null) { try { //数据库连接池的 Connection 对象进行 close 时 //并不是真的进行关闭, 而是把该数据库连接会归还到数据库连接池中. connection.close(); } catch (SQLException e) { e.printStackTrace(); } } } }
连接池DBCP&C3P0
package com.atguigu.jdbc; import java.beans.PropertyVetoException; import java.io.InputStream; 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; import com.mchange.v2.c3p0.ComboPooledDataSource; public class TestJDBC9 { /** * C3P0连接池 * @throws PropertyVetoException * @throws SQLException */ @Test public void testC3p0() throws PropertyVetoException, SQLException { ComboPooledDataSource cpds = new ComboPooledDataSource(); cpds.setDriverClass( "com.mysql.jdbc.Driver" ); //loads the jdbc driver cpds.setJdbcUrl( "jdbc:mysql:///hm_study" ); cpds.setUser("root"); cpds.setPassword("tiger"); System.out.println(cpds.getConnection()); } /**C3P0连接池 * 1. 创建 c3p0-config.xml 文件, 参考帮助文档中 Appendix B: Configuation Files 的内容 * 2. 创建 ComboPooledDataSource 实例; * DataSource dataSource = new ComboPooledDataSource("helloc3p0"); * 3. 从 DataSource 实例中获取数据库连接. */ @Test public void testC3p02() throws Exception{ DataSource dataSource = new ComboPooledDataSource("helloc3p0"); System.out.println(dataSource.getConnection()); ComboPooledDataSource comboPooledDataSource = (ComboPooledDataSource) dataSource; System.out.println(comboPooledDataSource.getMaxStatements()); } /**DBCP连接池 * 使用 DBCP 数据库连接池 * 1. 加入 jar 包(2 个jar 包). 依赖于 Commons Pool * 2. 创建数据库连接池 * 3. 为数据源实例指定必须的属性 * 4. 从数据源中获取数据库连接 * 测试最大连接数量 * @throws SQLException */ @Test public void testDBCP() throws SQLException{ final BasicDataSource dataSource = new BasicDataSource(); //2. 为数据源实例指定必须的属性 dataSource.setUsername("root"); dataSource.setPassword("tiger"); dataSource.setUrl("jdbc:mysql:///hm_study"); dataSource.setDriverClassName("com.mysql.jdbc.Driver"); //3. 指定数据源的一些可选的属性. //1). 指定数据库连接池中初始化连接数的个数 dataSource.setInitialSize(5); //2). 指定最大的连接数: 同一时刻可以同时向数据库申请的连接数 dataSource.setMaxActive(5); //3). 指定小连接数: 在数据库连接池中保存的最少的空闲连接的数量 dataSource.setMinIdle(2); //4).等待数据库连接池分配连接的最长时间. 单位为毫秒. 超出该时间将抛出异常. dataSource.setMaxWait(1000 * 5); //4. 从数据源中获取数据库连接 Connection connection = dataSource.getConnection(); System.out.println(connection.getClass()); connection = dataSource.getConnection(); System.out.println(connection.getClass()); connection = dataSource.getConnection(); System.out.println(connection.getClass()); connection = dataSource.getConnection(); System.out.println(connection.getClass()); Connection connection2 = dataSource.getConnection(); System.out.println(">" + connection2.getClass()); new Thread(){ public void run() { Connection conn; try { conn = dataSource.getConnection(); System.out.println(conn.getClass()); } catch (SQLException e) { e.printStackTrace(); } }; }.start(); try { Thread.sleep(5500); } catch (InterruptedException e) { e.printStackTrace(); } connection2.close(); } /**DBCP连接池 * 1. 加载 dbcp 的 properties 配置文件: 配置文件中的键需要来自 BasicDataSource的属性. * 2. 调用 BasicDataSourceFactory 的 createDataSource 方法创建 DataSource实例 * 3. 从 DataSource 实例中获取数据库连接. */ @Test public void testDBCP2() throws Exception{ Properties properties = new Properties(); InputStream inStream = getClass().getClassLoader().getResourceAsStream("dbcp.properties"); properties.load(inStream); DataSource dataSource = BasicDataSourceFactory.createDataSource(properties); System.out.println(dataSource.getConnection()); BasicDataSource basicDataSource = (BasicDataSource) dataSource; System.out.println(basicDataSource.getMaxWait()); } }
c3p0-config.xml
c3p0-config.xml
dbcp.properties
username=root
password=1230
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql:///hm_study
initialSize=10
maxActive=50
minIdle=5
maxWait=5000
示例2
批量插入数据
package com.atguigu.jdbc; import java.sql.Connection; import java.sql.Date; import java.sql.PreparedStatement; import org.junit.Test; import com.atguigu.util.JDBCTools; public class TestJDBC10 { /** * 批量插入数据 */ @Test public void testBatch(){ Connection connection = null; PreparedStatement preparedStatement = null; String sql = null; try { connection = JDBCTools.getConnection(); JDBCTools.beginTx(connection); sql = "INSERT INTO customers VALUES(?,?,?)"; preparedStatement = connection.prepareStatement(sql); Date date = new Date(new java.util.Date().getTime()); long begin = System.currentTimeMillis(); for(int i = 0; i < 100000; i++){ preparedStatement.setInt(1, i + 1); preparedStatement.setString(2, "name_" + i); preparedStatement.setDate(3, date); //"积攒" SQL preparedStatement.addBatch(); //当 "积攒" 到一定程度, 就统一的执行一次. 并且清空先前 "积攒" 的 SQL if((i + 1) % 300 == 0){ preparedStatement.executeBatch(); preparedStatement.clearBatch(); } } //若总条数不是批量数值的整数倍, 则还需要再额外的执行一次. if(100000 % 300 != 0){ preparedStatement.executeBatch(); preparedStatement.clearBatch(); } long end = System.currentTimeMillis(); System.out.println("Time: " + (end - begin)); //569 JDBCTools.commit(connection); } catch (Exception e) { e.printStackTrace(); JDBCTools.rollback(connection); } finally{ JDBCTools.releaseDB(null, preparedStatement, connection); } } }
DBUtils
示例3
利用DBUtils执行CRUD操作,对其中的数据记录进行封装
package com.atguigu.jdbc; import java.io.IOException; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import java.util.Map; import org.apache.commons.dbutils.QueryLoader; import org.apache.commons.dbutils.QueryRunner; import org.apache.commons.dbutils.ResultSetHandler; import org.apache.commons.dbutils.handlers.BeanListHandler; import org.apache.commons.dbutils.handlers.MapHandler; import org.apache.commons.dbutils.handlers.MapListHandler; import org.apache.commons.dbutils.handlers.ScalarHandler; import org.junit.Test; import com.atguigu.domain.User; import com.atguigu.util.JDBCTools; /** * 测试DBUtils工具类 * * @author Dell * */ public class TestJDBC11 { /** * 测试 QueryRunner 类的 update 方法 该方法可用于 INSERT, UPDATE 和 DELETE */ @Test public void test1() { // 创建QueryRunner 核心类对象 QueryRunner queryRunner = new QueryRunner(); String sql = "insert into user(username,password) values(?,?)"; Connection conn = null; try { conn = JDBCTools.getConnection(); queryRunner.update(conn, sql, "time", "computer"); } catch (Exception e) { e.printStackTrace(); } finally { JDBCTools.releaseDB(null, null, conn); } } /** * 推演(可忽略) 测试 QueryRunner 的 query 方法 */ @SuppressWarnings("all") @Test public void test2() { String sql = "select id,username,password from user"; Connection conn = null; QueryRunner queryRunner = new QueryRunner(); try { conn = JDBCTools.getConnection(); Object object = queryRunner.query(conn, sql, new ResultSetHandler() { @Override public Object handle(ResultSet rs) throws SQLException { List<User> users = new ArrayList<>(); while (rs.next()) { int id = rs.getInt(1); String username = rs.getString(2); String password = rs.getString(3); User user = new User(id, username, password); users.add(user); } return users; } }); System.out.println(object); } catch (Exception e) { e.printStackTrace(); } finally { JDBCTools.releaseDB(null, null, conn); } } /** * 查询多条记录 BeanListHandler 测试 ResultSetHandler 的 BeanListHandler 实现类 * BeanListHandler: 把结果集转为一个 Bean 的 List. 该 Bean 的类型在创建 BeanListHandler 对象时传入: * * new BeanListHandler<>(Customer.class) */ @Test public void test3() { String sql = "select id,username,password from user"; QueryRunner queryRunner = new QueryRunner(); Connection conn = null; try { conn = JDBCTools.getConnection(); List<User> list = queryRunner.query(conn, sql, new BeanListHandler<>(User.class)); for (User user : list) { System.out.println(user); } } catch (Exception e) { e.printStackTrace(); } finally { JDBCTools.releaseDB(null, null, conn); } } /** * MapHandler 查询一条记录,并把数据表中的字段和值,放入Map集合中 */ @Test public void test4() { String sql = "select id,username,password from user where id=?"; QueryRunner queryRunner = new QueryRunner(); Connection conn = null; try { conn = JDBCTools.getConnection(); Map<String, Object> map = queryRunner.query(conn, sql, new MapHandler(), 1); System.out.println(map); } catch (Exception e) { e.printStackTrace(); } finally { JDBCTools.releaseDB(null, null, conn); } } /** * MapListHandler 查询多条记录,并把数据表中的字段和值封装Map集合对象,然后放入List集合中 */ @Test public void test5() { String sql = "select id,username,password from user"; QueryRunner queryRunner = new QueryRunner(); Connection conn = null; try { conn = JDBCTools.getConnection(); List<Map<String, Object>> list = queryRunner.query(conn, sql, new MapListHandler()); for (Map<String, Object> map : list) { System.out.println(map); } } catch (Exception e) { e.printStackTrace(); } finally { JDBCTools.releaseDB(null, null, conn); } } /** * ScalarHandler 查询一条记录中某个字段的值 */ @Test public void test6() { String sql = "select username from user where id=?"; QueryRunner queryRunner = new QueryRunner(); Connection conn = null; try { conn = JDBCTools.getConnection(); Object username = queryRunner.query(conn, sql, new ScalarHandler(), 2); System.out.println(username); } catch (Exception e) { e.printStackTrace(); } finally { JDBCTools.releaseDB(null, null, conn); } } /** * 加载SQL脚本文件,执行其中的SQL语句 * * QueryLoader可以用来加载存放着 SQL 语句的资源文件. 使用该类可以把 SQL 语句外置化到一个资源文件中. 以提供更好的解耦 * @throws IOException */ @Test public void test7() throws IOException { // / 代表类路径的根目录. Map<String, String> sqls = QueryLoader.instance().load("/sql.properties"); String updateSql = sqls.get("UPDATE_USER"); System.out.println(updateSql); } /** * 1. ResultSetHandler 的作用: QueryRunner 的 query 方法的返回值最终取决于 query 方法的 * ResultHandler 参数的 hanlde 方法的返回值. * * 2. BeanListHandler: 把结果集转为一个 Bean 的 List, 并返回. Bean 的类型在 创建 BeanListHanlder * 对象时以 Class 对象的方式传入. 可以适应列的别名来映射 JavaBean 的属性名: String sql = "SELECT id, name * customerName, email, birth " + "FROM customers WHERE id = ?"; * * BeanListHandler(Class<T> type) * * 3. BeanHandler: 把结果集转为一个 Bean, 并返回. Bean 的类型在创建 BeanHandler 对象时以 Class * 对象的方式传入 BeanHandler(Class<T> type) * * 4. MapHandler: 把结果集转为一个 Map 对象, 并返回. 若结果集中有多条记录, 仅返回 第一条记录对应的 Map 对象. Map 的键: * 列名(而非列的别名), 值: 列的值 * * 5. MapListHandler: 把结果集转为一个 Map 对象的集合, 并返回. Map 的键: 列名(而非列的别名), 值: 列的值 * * 6. ScalarHandler: 可以返回指定列的一个值或返回一个统计函数的值. */ }
示例4
利用DBUtils抽取通用的DAO
package com.atguigu.dao; 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; import com.atguigu.jdbc.ReflectionUtils; /** * 使用 QueryRunner 提供其具体的实现 * @param <T>: 子类需传入的泛型类型. */ public class JdbcDaoImpl<T> implements DAO<T> { private QueryRunner queryRunner = null; private Class<T> type; public JdbcDaoImpl() { queryRunner = new QueryRunner(); type = ReflectionUtils.getSuperGenericType(getClass()); } /** * 批量处理的方法 * @param connection * @param sql * @param args: 填充占位符的 Object [] 类型的可变参数. * @throws SQLException */ @Override public void batch(Connection connection, String sql, Object[]... args) throws SQLException { queryRunner.batch(connection, sql, args); } /** * 返回数据表中某一个字段的值 * @param connection * @param sql * @param args * @return * @throws SQLException */ @Override public <E> E getForValue(Connection connection, String sql, Object... args) throws SQLException { return (E) queryRunner.query(connection, sql, new ScalarHandler(), args); } /** * 返回 T 的一个集合 * @param connection * @param sql * @param args * @return * @throws SQLException */ @Override public List<T> getForList(Connection connection, String sql, Object... args) throws SQLException { return queryRunner.query(connection, sql, new BeanListHandler<>(type), args); } /** * 返回一个 T 的对象 * @param connection * @param sql * @param args * @return * @throws SQLException */ @Override public T get(Connection connection, String sql, Object... args) throws SQLException { return queryRunner.query(connection, sql, new BeanHandler<>(type), args); } /** * INSRET, UPDATE, DELETE * @param connection: 数据库连接 * @param sql: SQL 语句 * @param args: 填充占位符的可变参数. * @throws SQLException */ @Override public void update(Connection connection, String sql, Object... args) throws SQLException { queryRunner.update(connection, sql, args); } }
ReflectionUtils
package com.atguigu.jdbc; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; /** * 反射的 Utils 函数集合 * 提供访问私有变量, 获取泛型类型 Class, 提取集合中元素属性等 Utils 函数 * @author Administrator * */ public class ReflectionUtils { /** * 通过反射, 获得定义 Class 时声明的父类的泛型参数的类型 * 如: public EmployeeDao extends BaseDao<Employee, String> * @param clazz * @param index * @return */ @SuppressWarnings("unchecked") public static Class getSuperClassGenricType(Class clazz, int index){ Type genType = clazz.getGenericSuperclass(); if(!(genType instanceof ParameterizedType)){ return Object.class; } Type [] params = ((ParameterizedType)genType).getActualTypeArguments(); if(index >= params.length || index < 0){ return Object.class; } if(!(params[index] instanceof Class)){ return Object.class; } return (Class) params[index]; } /** * 通过反射, 获得 Class 定义中声明的父类的泛型参数类型 * 如: public EmployeeDao extends BaseDao<Employee, String> * @param <T> * @param clazz * @return */ @SuppressWarnings("unchecked") public static<T> Class<T> getSuperGenericType(Class clazz){ return getSuperClassGenricType(clazz, 0); } /** * 循环向上转型, 获取对象的 DeclaredMethod * @param object * @param methodName * @param parameterTypes * @return */ public static Method getDeclaredMethod(Object object, String methodName, Class<?>[] parameterTypes){ for(Class<?> superClass = object.getClass(); superClass != Object.class; superClass = superClass.getSuperclass()){ try { //superClass.getMethod(methodName, parameterTypes); return superClass.getDeclaredMethod(methodName, parameterTypes); } catch (NoSuchMethodException e) { //Method 不在当前类定义, 继续向上转型 } //.. } return null; } /** * 使 filed 变为可访问 * @param field */ public static void makeAccessible(Field field){ if(!Modifier.isPublic(field.getModifiers())){ field.setAccessible(true); } } /** * 循环向上转型, 获取对象的 DeclaredField * @param object * @param filedName * @return */ public static Field getDeclaredField(Object object, String filedName){ for(Class<?> superClass = object.getClass(); superClass != Object.class; superClass = superClass.getSuperclass()){ try { return superClass.getDeclaredField(filedName); } catch (NoSuchFieldException e) { //Field 不在当前类定义, 继续向上转型 } } return null; } /** * 直接调用对象方法, 而忽略修饰符(private, protected) * @param object * @param methodName * @param parameterTypes * @param parameters * @return * @throws InvocationTargetException * @throws IllegalArgumentException */ public static Object invokeMethod(Object object, String methodName, Class<?> [] parameterTypes, Object [] parameters) throws InvocationTargetException{ Method method = getDeclaredMethod(object, methodName, parameterTypes); if(method == null){ throw new IllegalArgumentException("Could not find method [" + methodName + "] on target [" + object + "]"); } method.setAccessible(true); try { return method.invoke(object, parameters); } catch(IllegalAccessException e) { System.out.println("不可能抛出的异常"); } return null; } /** * 直接设置对象属性值, 忽略 private/protected 修饰符, 也不经过 setter * @param object * @param fieldName * @param value */ public static void setFieldValue(Object object, String fieldName, Object value){ Field field = getDeclaredField(object, fieldName); if (field == null) throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + object + "]"); makeAccessible(field); try { field.set(object, value); } catch (IllegalAccessException e) { System.out.println("不可能抛出的异常"); } } /** * 直接读取对象的属性值, 忽略 private/protected 修饰符, 也不经过 getter * @param object * @param fieldName * @return */ public static Object getFieldValue(Object object, String fieldName){ Field field = getDeclaredField(object, fieldName); if (field == null) throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + object + "]"); makeAccessible(field); Object result = null; try { result = field.get(object); } catch (IllegalAccessException e) { System.out.println("不可能抛出的异常"); } return result; } }
示例5(忽略)
调用存储过程
/** * 如何使用 JDBC 调用存储在数据库中的函数或存储过程 */ @Test public void test1() { Connection connection = null; CallableStatement callableStatement = null; try { connection = JDBCTools.getConnection(); // 1. 通过 Connection 对象的 prepareCall() // 方法创建一个 CallableStatement 对象的实例. // 在使用 Connection 对象的 preparedCall() 方法时, // 需要传入一个 String 类型的字符串, 该字符串用于指明如何调用存储过程. String sql = "{?= call sum_salary(?, ?)}"; callableStatement = connection.prepareCall(sql); // 2. 通过 CallableStatement 对象的 //reisterOutParameter() 方法注册 OUT 参数. callableStatement.registerOutParameter(1, Types.NUMERIC); callableStatement.registerOutParameter(3, Types.NUMERIC); // 3. 通过 CallableStatement 对象的 setXxx() 方法设定 IN 或 IN OUT 参数. 若想将参数默认值设为 // null, 可以使用 setNull() 方法. callableStatement.setInt(2, 80); // 4. 通过 CallableStatement 对象的 execute() 方法执行存储过程 callableStatement.execute(); // 5. 如果所调用的是带返回参数的存储过程, //还需要通过 CallableStatement 对象的 getXxx() 方法获取其返回值. double sumSalary = callableStatement.getDouble(1); long empCount = callableStatement.getLong(3); System.out.println(sumSalary); System.out.println(empCount); } catch (Exception e) { e.printStackTrace(); } finally { JDBCTools.releaseDB(null, callableStatement, connection); } }
zwy

浙公网安备 33010602011771号