目录
2 使用QueryRunner类,实现数据的添加、更新、删除
3 使用ResultSetHandler接口的4个实现类处理数据查询结果
4.1 关于DataSource接口、QueryRunner类的梳理总结
1 概述
JDBC 开发模板形式的代码,6步骤固定,代码重复,DBUtils就是为了简化JDBC发开而来。
Dbutils三个核心功能介绍
(1)QueryRunner类中提供对sql语句操作的API。可以把QueryRunner对象理解成JDBC中的“sql语句执行对象”
(2)ResultSetHandler接口,用于在执行查询操作后,怎样封装结果集。对于该接口,有如下4个实现类,这四个实现类实现了对于sql查询结果的不同封装。
① BeanHandler:把查询结果中的第一行数据,存储到JavaBean对象中
② BeanListHandler:把查询结果中的每一行数据,存储到JavaBean对象的List集合中
③ ColumnListHandler:把查询数据表中的一个列的数据,存储到List集合中
④ ScalarHandler:适合单值查询,结果集只有一个值,比如count(*)
(3)DbUtils类,它是一个工具类,定义了关闭资源与事务处理的方法。
如下的内容主要针对QueryRunner类的使用以及ResultSetHandler接口的四个实现类的使用方法进行介绍。
2 使用QueryRunner类,实现数据的添加、更新、删除
/**
* 使用DBUtils工具类,实现数据的插入、更新、删除
* 核心类:QueryRunner执行SQL语句
* QueryRunner对象的创建有两种方法:要么用它的无参构造(这个java文件采用这个方法),要么手传一个DataSource接口的实现类对象到有参构造中
* 当数据库操作涉及到“事务”时,需要用无参构造的方式创建QueryRunner对象,然后在执行sql的时候再多传入一个连接对象就好了。
* 这样才能保证“数据库连接对象在自己手中,而不是刚一开始创建QueryRunner接口实现类对象时就把数据库连接对象藏起来了
* (数据库连接对象的获取需要通过QueryRunner接口实现类对象的.getConnection()方法)”
* 1、创建对象
* (1)无参构造,直接new
* (2)QueryRunner(DataSource ds) 传递DataSource接口实现类对象
* 2、调用方法update
* int update(连接对象,sql语句,sql语句中的问号占位符...)
*/
public class DBUtilsDemo {
public static void main(String[] args) throws SQLException {
//insert();
//update();
delete();
}
//实现数据的添加
public static void insert() throws SQLException {
//创建QueryRunner对象
QueryRunner queryRunner = new QueryRunner();
//拼写sql,用于插入数据
String sql = "insert into Product values(?,?,?,?)";
//执行update方法
//把sql语句中的参数存在数组中,提升代码的可读性和可维护性(3个及以上可以用数组)
Object[] params = {null, "新手机", 29999, "c001"};
int rows = queryRunner.update(DruidUtils.getConnection(), sql, params);
System.out.println(rows);
//不用释放资源了,DBUtils自动帮我们完成这个操作
}
//实现数据更新
public static void update() throws SQLException {
//创建QueryRunner对象
QueryRunner queryRunner = new QueryRunner();
//拼写sql,用于更新数据
String sql = "update Product set pname =?, price=?,category_id = ? where pid = ?";
//问号中的参数定义在数组中
Object[] params = {"新手机2", 39999, "c001",15};
int rows = queryRunner.update(DruidUtils.getConnection(), sql, params);
System.out.println(rows);
//不用释放资源了,DBUtils自动帮我们完成这个操作
}
//实现删除数据
public static void delete() throws SQLException {
//创建QueryRunner对象
QueryRunner queryRunner = new QueryRunner();
//拼写sql,用于更新数据
String sql = "delete from Product where pid = ?";
int rows = queryRunner.update(DruidUtils.getConnection(), sql, 14);
System.out.println(rows);
//不用释放资源了,DBUtils自动帮我们完成这个操作
}
}
3 使用ResultSetHandler接口的4个实现类处理数据查询结果
/**
* 实现利用dbutils实现查询前的准备工作
* 1、QueryRunner构造方法中,除了那个无参的,还有个带参数的构造
* QueryRunner(DataSource ds) 传递DataSource接口实现类对象
* <p>
* 2、JavaBean对象
* 对于一个类,如果包含私有成员变量、get/set方法、无参构造,则被称为JavaBean对象
* 应该可以被序列化(目前省略)
* <p>
* QueryRunner类的方法:query执行查询
* query(sql语句,ResultSetHandler接口实现类对象,sql语句中问号占位符参数...)
* ResultSetHandler表示查询后的结果集是什么,其实就是对查询后的结果集进行了一定的转换
* 接口实现类:
* BeanHandler:把查询结果中的第一行数据,存储到JavaBean对象中
* BeanListHandler:把查询结果中的每一行数据,存储到JavaBean对象的List集合中
* ColumnListHandler:把查询数据表中的一个列的数据,存储到List集合中
* ScalarHandler:适合单值查询,结果集只有一个值,比如count(*)
*/
public class DBUtilsDemo02 {
public static void main(String[] args) throws SQLException {
//beanHandler();
//beanListHandler();
//columnListHandler();
scalarHandler();
}
//BeanHandler:把查询结果中的第一行数据,存储到JavaBean(Priduct)对象中
public static void beanHandler() throws SQLException {
//创建QueryRunner类对象,有参构造方法,传递DataSource接口实现类
QueryRunner queryRunner = new QueryRunner(DruidUtils.getDataSource()); //有参构造创建对象,参数是数据库连接对象,后面的方法中就不用再传入连接了
String sql = "select * from product";
//调用方法query执行sql语句
//BeanHandle对象的创建需要传入“JavaBean的class文件对象”
Product product = queryRunner.query(sql, new BeanHandler<Product>(Product.class));//这里用到了反射:先拿到JavaBean的class文件对象,然后通过反射调用其get、set方法往把查询结果传到JavaBean(Product对象)中
System.out.println(product);
}
//BeanListHandler:把查询结果中的每一行数据,存储到JavaBean对象的List集合中
public static void beanListHandler() throws SQLException {
//创建QueryRunner类对象,有参构造方法,传递DataSource接口实现类
QueryRunner queryRunner = new QueryRunner(DruidUtils.getDataSource()); //有参构造创建对象,参数是数据库连接对象,后面的方法中就不用再传入连接了
String sql = "select * from product";
//调用方法query执行sql语句
//BeanHandle对象的创建需要传入“JavaBean的class文件对象”
List<Product> productList = queryRunner.query(sql, new BeanListHandler<Product>(Product.class));//这里用到了反射:先拿到JavaBean的class文件对象,然后通过反射调用其get、set方法往把查询结果传到JavaBean(Product对象)中
for (Product product : productList) {
System.out.println(product);
}
}
//ColumnListHandler:把查询数据表中的一个列的数据,存储到List集合中
public static void columnListHandler() throws SQLException {
//创建QueryRunner类对象,有参构造方法,传递DataSource接口实现类
QueryRunner queryRunner = new QueryRunner(DruidUtils.getDataSource()); //有参构造创建对象,参数是数据库连接对象,后面的方法中就不用再传入连接了
String sql = "select * from product";
//执行查询语句,传递的对象是ColumnListHandler,只要查询结果中的一个列
List<Object> pnameList = queryRunner.query(sql, new ColumnListHandler<Object>("pname"));//泛型传一个Object,因为有可能不知道该列所对应的数据类型
for (Object o : pnameList) {
System.out.println(o);
}
}
//ScalarHandler:适合单值查询(聚合函数),结果集只有一个值,比如count(*)
public static void scalarHandler() throws SQLException {
//创建QueryRunner类对象,有参构造方法,传递DataSource接口实现类
QueryRunner queryRunner = new QueryRunner(DruidUtils.getDataSource()); //有参构造创建对象,参数是数据库连接对象,后面的方法中就不用再传入连接了
String sql = "select count(pid) from product";
Object object = queryRunner.query(sql, new ScalarHandler<Object>()); //也可以用Long
System.out.println(object);
}
}
4 总结与注意点
4.1 关于DataSource接口、QueryRunner类的梳理总结
(1)DataSource接口
DataSource接口是数据库连接池的标准规范,如果你觉得JDBC连接获取数据库连接对象太慢了,
想自己开发一个数据库连接池达到“共享”数据库连接对象的目的的话,就必须实现DataSource这个接口。
在C3P0中,DataSource接口的实现类对象是直接“new”出来的,而在Druid中这个对象是通过调用DruidDataSourceFactory工厂类的createDataSource方法获取到的。
DataSource接口实现类对象的 getConnection() 方法可以获取数据库连接对象。
(2)QueryRunner类(DBUtils工具包中的类,为了简化JDBC操作数据库复杂的流程)
QueryRunner类中提供了对sql语句进行操作的API。可以把QueryRunner对象理解成JDBC中的“sql语句执行对象”。
但是获取QueryRunner对象有两个:要么用它的无参构造,要么传一个DataSource接口的实现类对象到有参构造中。
4.2 注意点
当数据库操作涉及到“事务”,且准备要用DBUtils来简化操作步骤时,这就要注意了:
因为“事务”的操作需要用到“数据库连接对象”,而QueryRunner类对象的创建,可以通过那个带参的构造函数来完成,
但是问题来了:这个带参的构造函数传的参数是“DataSource接口的实现类对象”,这样好像直接“跳过”了数据库连接对象!(比如DBUtilsDemo02.java 就用了带参构造)
因此,当数据库操作涉及到“事务”,且准备要用DBUtils来简化操作步骤时,需要使用QueryRunner类的无参构造方法创建对象,
从而把“数据库连接对象”暴露出来,让后面的“事务”可以去使用它。