1. Apache-DBUtils简介
- commons-dbutils 是 Apache 组织提供的一个开源 JDBC工具类库,它是对JDBC的简单封装,学习成本极低,并且使用dbutils能极大简化jdbc编码的工作量,同时也不会影响程序的性能。
- API介绍:
(1)org.apache.commons.dbutils.QueryRunner
(2)org.apache.commons.dbutils.ResultSetHandler
(3)工具类:org.apache.commons.dbutils.DbUtils
2. 主要API的使用
DbUtils
- DbUtils :提供如关闭连接、装载JDBC驱动程序等常规工作的工具类,里面的所有方法都是静态的。主要方法如下:
(1)public static void close(…) throws java.sql.SQLException: DbUtils类提供了三个重载的关闭方法。这些方法检查所提供的参数是不是NULL,如果不是的话,它们就关闭Connection、Statement和ResultSet。
(2)public static void closeQuietly(…): 这一类方法不仅能在Connection、Statement和ResultSet为NULL情况下避免关闭,还能隐藏一些在程序中抛出的SQLEeception。
(3)public static void commitAndClose(Connection conn)throws SQLException: 用来提交连接的事务,然后关闭连接
(4)public static void commitAndCloseQuietly(Connection conn): 用来提交连接,然后关闭连接,并且在关闭连接时不抛出SQL异常。
(5)public static void rollback(Connection conn)throws SQLException:允许conn为null,因为方法内部做了判断
(6)public static void rollbackAndClose(Connection conn)throws SQLException
(7)rollbackAndCloseQuietly(Connection)
(8)public static boolean loadDriver(java.lang.String driverClassName):这一方装载并注册JDBC驱动程序,如果成功就返回true。使用该方法,你不需要捕捉这个异常ClassNotFoundException。
QueryRunner类
- 该类简单化了SQL查询,它与ResultSetHandler组合在一起使用可以完成大部分的数据库操作,能够大大减少编码量。
- QueryRunner类提供了两个构造器:
(1)默认的构造器
(2)需要一个 javax.sql.DataSource 来作参数的构造器- QueryRunner类的主要方法:
更新
(1)public int update(Connection conn, String sql, Object... params) throws SQLException:用来执行一个更新(插入、更新或删除)操作。
(2)......
插入
(1)public T insert(Connection conn,String sql,ResultSetHandler rsh, Object... params) throws SQLException:只支持INSERT语句,其中 rsh - The handler used to create the result object from the ResultSet of auto-generated keys. 返回值: An object generated by the handler.即自动生成的键值
(2)....
批处理
(1)public int[] batch(Connection conn,String sql,Object[][] params)throws SQLException: INSERT, UPDATE, or DELETE语句
(2)public T insertBatch(Connection conn,String sql,ResultSetHandler rsh,Object[][] params)throws SQLException:只支持INSERT语句
(3).....
查询
(1)public Object query(Connection conn, String sql, ResultSetHandler rsh,Object... params) throws SQLException:执行一个查询操作,在这个查询中,对象数组中的每个元素值被用来作为查询语句的置换参数。该方法会自行处理 PreparedStatement 和 ResultSet 的创建和关闭。
(2)......
ResultSetHandler接口及实现类
- 该接口用于处理 java.sql.ResultSet,将数据按要求转换为另一种形式。
- ResultSetHandler 接口提供了一个单独的方法:Object handle (java.sql.ResultSet .rs)。
- 接口的主要实现类:
(1)ArrayHandler:把结果集中的第一行数据转成对象数组。
(2)ArrayListHandler:把结果集中的每一行数据都转成一个数组,再存放到List中。
(3)BeanHandler:将结果集中的第一行数据封装到一个对应的JavaBean实例中。
(4)BeanListHandler:将结果集中的每一行数据都封装到一个对应的JavaBean实例中,存放到List里。
(5)ColumnListHandler:将结果集中某一列的数据存放到List中。
(6)KeyedHandler(name):将结果集中的每一行数据都封装到一个Map里,再把这些map再存到一个map里,其key为指定的key。
(7)MapHandler:将结果集中的第一行数据封装到一个Map里,key是列名,value就是对应的值。
(8)MapListHandler:将结果集中的每一行数据都封装到一个Map里,然后再存放到List
(9)ScalarHandler:查询单个值对象
代码示例(使用QueryRunner实现增删改查以及查询特殊值的操作)
package com.lty5.dbutils;
import java.sql.Connection;
import java.sql.Date;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
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.MapHandler;
import org.apache.commons.dbutils.handlers.MapListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;
import org.junit.Test;
import com.lty2.bean.Customer;
import com.lty4.util.JDBCUtils;
/**
* commons-dbutils 是 Apache 组织提供的一个开源 JDBC工具类库,封装了针对于数据库的增、删、改、查操作
*/
public class QueryRunnerTest {
// 测试插入
@Test
public void testInsert() {
Connection conn = null;
try {
QueryRunner runner = new QueryRunner();
conn = JDBCUtils.getConnection3();
String sql = "insert into customers(name , email , birth)values(?,?,?)";
int insertCount = runner.update(conn, sql, "蔡徐坤", "[email protected]", "1997-05-08");
System.out.println("添加了" + insertCount + "条记录");
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.closeResource(conn, null);
}
}
// 测试查询
/*
* BeanHandler : 是ResultSetHandler接口的实现类,用于封装表中的一条记录
*/
@Test
public void testQuery1() {
Connection conn = null;
try {
QueryRunner runner = new QueryRunner();
conn = JDBCUtils.getConnection3();
String sql = "select id , name , email , birth from customers where id = ?";
BeanHandler handler = new BeanHandler<>(Customer.class);
Customer customer = runner.query(conn, sql, handler, 31);
System.out.println(customer);
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.closeResource(conn, null);
}
}
/*
* BeanListHandler : 是ResultSetHandler接口的实现类,用于封装表中的多条记录构成的集合
*/
@Test
public void testQuery2() {
Connection conn = null;
try {
QueryRunner runner = new QueryRunner();
conn = JDBCUtils.getConnection3();
String sql = "select id , name , email , birth from customers where id < ?";
BeanListHandler handler = new BeanListHandler<>(Customer.class);
List list = runner.query(conn, sql, handler, 31);
list.forEach(System.out::println);
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.closeResource(conn, null);
}
}
/*
* MapHandler : 是ResultSetHandler接口的实现类,对应表中的一条记录(通过键 值 的形式)
* --- 将字段及相应字段的值作为map中的键和值(key 和 value)
*/
@Test
public void testQuery3() {
Connection conn = null;
try {
QueryRunner runner = new QueryRunner();
conn = JDBCUtils.getConnection3();
String sql = "select id , name , email , birth from customers where id = ?";
MapHandler handler = new MapHandler();
Map map = runner.query(conn, sql, handler, 31);
System.out.println(map);
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.closeResource(conn, null);
}
}
/*
* MapListHandler : 是ResultSetHandler接口的实现类,对应表中的多条记录(通过键 值 的形式)
* --- 将字段及相应字段的值作为map中的键和值(key 和 value),将这些map添加到List中
*/
@Test
public void testQuery4() {
Connection conn = null;
try {
QueryRunner runner = new QueryRunner();
conn = JDBCUtils.getConnection3();
String sql = "select id , name , email , birth from customers where id < ?";
MapListHandler handler = new MapListHandler();
List
使用Druid数据库连接池技术获取数据库连接
package com.lty4.util;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
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 org.apache.commons.dbcp.BasicDataSourceFactory;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import com.mchange.v2.c3p0.ComboPooledDataSource;
public class JDBCUtils {
/**
* 获取数据库的连接
*/
public static Connection getConnection() throws Exception {
// 1.读取配置文件中的4个基本信息
// ClassLoader.getSystemClassLoader() : 获取系统类加载器
InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("jdbc.properties");
Properties pros = new Properties();
pros.load(is);
String user = pros.getProperty("user");
String password = pros.getProperty("password");
String url = pros.getProperty("url");
String driverClass = pros.getProperty("driverClass");
// 2.加载驱动
Class.forName(driverClass);
// 3.获取连接
Connection conn = DriverManager.getConnection(url, user, password);
return conn;
}
/**
* 使用C3P0的数据库连接池技术
*/
// 数据库连接池只需提供一个即可 放在外面的好处? --- > 随着工具(当前)类的调用而被立即创建实例化对象,当存在同时多个调用时,该实例化对象始终是这一个,避免了调用一次创建一次实例化对象的过程
private static ComboPooledDataSource cpds = new ComboPooledDataSource("hellc3p0"); // 创造c3p0数据库连接池
public static Connection getConnection1() throws SQLException {
Connection conn = cpds.getConnection();
return conn;
}
/**
* 使用DBCP数据库连接池技术来获取数据库连接
*/
// 创建一个DBCP数据库连接池
private static DataSource source;
// 静态代码块随着类的加载而加载,只执行一次
static {
try {
Properties pros = new Properties();
// 方式一 :使用类的加载器获取系统类加载器
// InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("dbcp.properties"); // 默认识别src下
// 方式二
FileInputStream is = new FileInputStream(new File("src/dbcp.properties")); // 识别的是当前工程下
pros.load(is);
source = BasicDataSourceFactory.createDataSource(pros);
} catch (Exception e) {
e.printStackTrace();
}
}
public static Connection getConnection2() throws Exception {
Connection conn = source.getConnection();
return conn;
}
/**
* 使用Druid数据库连接池技术
*/
private static DataSource source1;
static {
try {
Properties pros = new Properties();
InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("druid.properties");
pros.load(is);
source1 = DruidDataSourceFactory.createDataSource(pros);
} catch (Exception e) {
e.printStackTrace();
}
}
public static Connection getConnection3() throws Exception {
Connection conn = source1.getConnection();
return conn;
}
/**
* 关闭资源的操作
*/
public static void closeResource(Connection conn , Statement ps) {
try {
if (conn != null)
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
try {
if (ps != null)
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
// 关闭资源操作
public static void closeResource(Connection conn , Statement ps , ResultSet rs) {
try {
if (conn != null)
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
try {
if (ps != null)
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
try {
if (rs != null)
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
Customer实体类
package com.lty2.bean;
import java.sql.Date;
/**
* ORM编程思想 : Object Relational Mapping (对象关系映射)
* 具体体现: 我们需要让一个数据表对应一个Java类
* 表中的一条记录对应Java类的一个对象
* 表中的一个字段对应Java类的一个属性
*/
public class Customer {
private int id;
private String name;
private String email;
private Date birth;
public Customer() {
super();
}
public Customer(int id, String name, String email, Date birth) {
super();
this.id = id;
this.name = name;
this.email = email;
this.birth = birth;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Date getBirth() {
return birth;
}
public void setBirth(Date birth) {
this.birth = birth;
}
@Override
public String toString() {
return "Customer [id=" + id + ", name=" + name + ", email=" + email + ", birth=" + birth + "]";
}
}
自定义ResultSetHandler的实现类完成指定操作(单个方法)
/*
* 自定义ResultSetHandler的实现类
*/
@Test
public void testQuery7() {
Connection conn = null;
try {
QueryRunner runner = new QueryRunner();
conn = JDBCUtils.getConnection3();
String sql = "select id , name , email , birth from customers where id = ?";
ResultSetHandler handler = new ResultSetHandler() {//匿名实现类
@Override
public Customer handle(ResultSet rs) throws SQLException {
// System.out.println("handle");
if(rs.next()) {
int id = rs.getInt("id");
String name = rs.getString("name");
String email = rs.getString("email");
Date birth = rs.getDate("birth");
Customer customer = new Customer(id, name , email, birth);
return customer;
}
return null;
}
};
Customer customer = runner.query(conn, sql, handler, 31);
System.out.println(customer);
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.closeResource(conn, null);
}
}
使用DbUtils工具类实现关闭资源的操作(单个方法)
// 使用dbutils.jar中提供的DbUtils工具类,实现资源的关闭
public static void closeResource1(Connection conn , Statement ps , ResultSet rs) {
// 方式一
// try {
// DbUtils.close(conn);
// } catch (SQLException e) {
// e.printStackTrace();
// }
//
// try {
// DbUtils.close(ps);
// } catch (SQLException e) {
// e.printStackTrace();
// }
//
// try {
// DbUtils.close(rs);
// } catch (SQLException e) {
// e.printStackTrace();
// }
// 方式二
DbUtils.closeQuietly(conn);
DbUtils.closeQuietly(ps);
DbUtils.closeQuietly(rs);
}