DBUtils
标签(空格分隔): jdbc
DBUtils简介
DBUtils是什么
DButils:由Apache公司提供,一个对JDBC进行简单封装的开源工具类库,简化dao层的操作。
作用:帮助java程序员,开发Dao层代码的简单框架。
框架的作用:帮助程序员,提高程序的开发效率。
为什么需要DBUtils
在使用Dbutils 之前,我们在Dao层使用的技术是JDBC,那么分析一下JDBC的弊端:
- 数据库链接对象、sql语句操作对象,封装结果集对象,这三大对象会重复定义
- 封装数据的代码重复,而且操作复杂,代码量大
- 释放资源的代码重复
因此我们使用已经封装好的工具类库进行操作,能够减少重复劳动。
DBUtils三个核心类
DBUtils类
DbUtils :提供如关闭连接、装载JDBC驱动程序等常规工作的工具类,里面的所有方法都是静态的。主要方法如下:
public static void close(…) throws java.sql.SQLException
: DbUtils类提供了三个重载的关闭方法。这些方法检查所提供的参数是不是NULL,如果不是的话,它们就关闭Connection、Statement和ResultSet。public static void closeQuietly(…)
: 这一类方法不仅能在Connection、Statement和ResultSet为NULL情况下避免关闭,还能隐藏一些在程序中抛出的SQLEeception。public static void commitAndCloseQuietly(Connection conn)
: 用来提交连接,然后关闭连接,并且在关闭连接时不抛出SQL异常。public static boolean loadDriver(java.lang.String driverClassName)
:这一方装载并注册JDBC驱动程序,如果成功就返回true。使用该方法,你不需要捕捉这个异常ClassNotFoundException。
QueryRunner类
该类简单化了SQL查询,是SQL语句的操作对象。它与ResultSetHandler组合在一起使用可以完成大部分的数据库操作,可以设置查询结果集的封装策略,线程安全。能够大大减少编码量。
QueryRunner类提供了两类构造方法:
QueryRunner()
:创建一个与数据库无关的QueryRunner对象,在操作数据库的时候,需要手动给一个Connection对象,它可以手动控制事务(setAutoCommit(false)方法设置手动管理事物和commit()方法提交事物)。QueryRunner(DataSource ds)
: 创建一个与数据库关联的QueryRunner对象,后期再操作数据库的时候,不需要Connection对象,自动管理事务。DataSource是数据库连接池对象。
ResultSetHandler接口
该接口用于处理 java.sql.ResultSet,将数据按要求转换为另一种形式。
ResultSetHandler 接口提供了一个单独的方法:Object handle (java.sql.ResultSet .rs)
。
ResultSetHandler 接口的实现类
ArrayHandler
:把结果集中的第一行数据转成对象数组。ArrayListHandler
:把结果集中的每一行数据都转成一个数组,再存放到List中。BeanHandler
:将结果集中的第一行数据封装到一个对应的JavaBean实例中。BeanListHandler
:将结果集中的每一行数据都封装到一个对应的JavaBean实例中,存放到List里。ColumnListHandler
:将结果集中某一列的数据存放到List中。KeyedHandler(name)
:将结果集中的每一行数据都封装到一个Map里,再把这些map再存到一个map里,其key为指定的key。MapHandler
:将结果集中的第一行数据封装到一个Map里,key是列名,value就是对应的值。MapListHandler
:将结果集中的每一行数据都封装到一个Map里,然后再存放到List
update方法
用来执行一个更新(插入、更新或删除)操作。
int update(Connection conn, String sql)
int update(Connection conn, String sql, Object... params)
int update(String sql)
int update(String sql, Object... params)
测试update方法,步骤如下:
1. 要创建一个QueryRunner类的对象
2. 创建sql语句
3. 建立Connection连接(使用C3P0数据源)
4. 调用QueryRunner对象的update方法
/**
* 测试QueryRunner类的update方法
*/
@Test
public void testQueryRunnerUpdate() {
//1. 创建QueryRunner的实现类
QueryRunner queryRunner = new QueryRunner();
String sql = "DELETE FROM customers WHERE id IN (?,?)";
Connection connection = null;
try {
connection = JDBCTools.getConnection();
//2. 使用其update方法
queryRunner.update(connection,sql,9,10);
} catch (SQLException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCTools.releaseDB(null,null,connection);
}
}
query方法
query方法的API
执行一个查询操作。
<T> T query(Connection conn, String sql, ResultSetHandler<T> rsh)
<T> T query(Connection conn, String sql, ResultSetHandler<T> rsh, Object... params)
<T> T query(String sql, ResultSetHandler<T> rsh)
<T> T query(String sql, ResultSetHandler<T> rsh, Object... params)
query方法的工作原理
下面我们来看一组测试代码:
//创建一个QueryRunner的对象
QueryRunner queryRunner = new QueryRunner();
//一个内部类继承ResultSetHandler,实现handle函数
class MyResultSetHandler implements ResultSetHandler{
public Object handle(ResultSet resultSet) {
System.out.println("handle....");
return "hahaha";
}
}
//QueryRunner 的 quey方法的返回值取决于其ResultSetHandler参数的handle方法的返回值
@Test
public void testQuery() {
Connection connection = null;
try {
connection = JDBCTools.getConnection();
String sql = "SELECT id,name,email,birth FROM customers";
//QueryRunner对象的query函数,传递三个参数,并有一个返回值
Object object = queryRunner.query(connection,sql,new MyResultSetHandler());
System.out.println(object);
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCTools.releaseDB(null,null,connection);
}
}
//
分析:
我们有一个QueryRunner类,这个类有一个query方法:
query(Connection conn,String sql,ResultSetHandler rsh) {
//获取连接和操作sql的对象
stmt = this.prepareStatement(conn, sql);
//填充占位符
this.fillStatement(stmt, params);
//进行查询,获取结果集对象
rs = this.wrap(stmt.executeQuery());
//调用传入的ResultSetHandler对象的handle方法,并且把前面得到的ResultSet对象作为参数传入
result = rsh.handle(rs);
//把result作为结果返回
return result;
}
那么我们在以上代码中MyResultSetHandler类的handle方法中,并没有处理传入的ResultSet对象,而是直接返回了一个字符串。因此query(Connection conn,String sql,ResultSetHandler rsh)
方法中返回的就是字符串。
因此我们得到一个重要的结论:
QueryRunner 的 quey方法的返回值取决于其ResultSetHandler参数的handle方法的返回值
handle方法的功能
因此我们重新写一下MyResultSetHandler类的handle方法,令其查询结果集,并将每一条结果集得到的列作为参数传递给对象的构造函数,并加入到集合中。最终返回集合:
class MyResultSetHandler implements ResultSetHandler{
public Object handle(ResultSet resultSet) throws SQLException {
List<Customer> customers = new ArrayList<>();
while (resultSet.next()) {
Integer id = resultSet.getInt(1);
String name = resultSet.getString(2);
String email = resultSet.getString(3);
String birth = resultSet.getString(4);
Customer customer = new Customer(id,name,email,birth);
customers.add(customer);
}
return customers;
}
}
我们重新梳理一下QueryRunner类的query方法:
1. Object object = queryRunner.query(connection,sql,new MyResultSetHandler());
该方法返回一个对象
2. query(Connection conn,String sql,ResultSetHandler rsh)
方法第三个参数是ResultSetHandler的一个对象
3. ResultSetHandler对象的作用是调用这个对象的handle方法,用这个方法来处理结果集
4. 因此我们要在handle方法中写入对结果集的处理
实用的Handler方法
BeanHandler()
BeanHandler:把结果集的第一条记录转为创建BeanHandler对象时传入的Class参数对应的对象,返回的是处理完的对象
public void testBeanHandler() {
Connection connection = null;
try {
connection = JDBCTools.getConnection();
String sql = "SELECT id,name,email,birth FROM customers WHERE id = ?";
//BeanHandler传入的参数为Customer.class
Customer customer = queryRunner.query(connection,sql,
new BeanHandler<Customer>(Customer.class),5);
System.out.println(customer);
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCTools.releaseDB(null,null,connection);
}
}
BeanListHandler()
BeanListHandler:把结果集转为一个List,该List不为null,但可能为空集合(size()方法返回0)
若SQL语句的确能够查询到记录,List中存放创建BeanListHandler传入的Class对象对应的对象。
public void testBeanListHandler() {
Connection connection = null;
try {
connection = JDBCTools.getConnection();
String sql = "SELECT id,name,email,birth FROM customers";
//BeanListHandler传入的Class对象
List<Customer> customers = queryRunner.query(connection,sql,new BeanListHandler<Customer>(Customer.class));
System.out.println(customers);
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCTools.releaseDB(null,null,connection);
}
}
MapHandler()
MapHandler():返回SQL对应的第一条记录对应的map对象
键:SQL查询的列名(不是别名),值:列的值
@Test
public void testMapHandler() {
Connection connection = null;
try {
connection = JDBCTools.getConnection();
String sql = "SELECT id,name,email,birth FROM customers";
//直接传入MapHandler()对象
Map<String,Object> customers = queryRunner.query(connection,sql,new MapHandler());
System.out.println(customers);
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCTools.releaseDB(null,null,connection);
}
}
MapListHandler()
MapListHandler():将结果集转为一个Map的List,Map对应查询的一条记录
键:SQL查询的列名(不是别名),值:列的值。
而MapListHandler返回的是多条记录对应的Map的集合。且在MapListHandler()的handle方法中,直接对集合进行了循环添加。
@Test
public void testMapListHandler() {
Connection connection = null;
try {
connection = JDBCTools.getConnection();
String sql = "SELECT id,name,email,birth FROM customers";
List<Map<String,Object>> customers = queryRunner.query(connection,sql,new MapListHandler());
System.out.println(customers);
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCTools.releaseDB(null,null,connection);
}
}
ScalarHandler
ScalarHandler:把结果集转为一个数值(可以是任意基本数据类型和字符串,Date等),返回
@Test
public void testScalarHandler() {
Connection connection = null;
try {
connection = JDBCTools.getConnection();
String sql = "SELECT COUNT(id) FROM customers";
Object result = queryRunner.query(connection,sql,
new ScalarHandler<>());
System.out.println(result);
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCTools.releaseDB(null,null,connection);
}
}