package com.jdbc.dbutils;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.ResultSetHandler;
import org.apache.commons.dbutils.handlers.*;
import org.junit.Test;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* 1、DbUtils 简介:
* DbUtils 是 java 编程中的数据库操作实用工具,小巧、简单、实用;
* DbUtils 封装了对 JDBC 的操作,简化了 JDBC 操作,可以少写代码;
*
* 对于数据库的读操作,DbUtils 可以把结果直接转换成 List、Array、Set 等 java 集合,便于程序员操作;
* 对于数据库的写操作,也变的很简单,只需要写 sql 语句;
* 可以使用 数据源、JNDI、数据库连接池 等技术来优化性能 -- 重用已经构建好的数据库连接对象;
*
* 2、DbUtils 的核心对象:
* QueryRunner 类:提供对 sql 语句操作的 API;
* query():用于执行 select 语句;
* update():用于执行 insert、update、delete 语句;
* batch():批处理;
* ResultSetHandler 接口:用于定义 select 操作后,怎样封装结果集;
* DbUtils 类:他就是一个工具类,定义了关闭资源与事务处理的方法;
*
* 3、DbUtils 导入的 jar 包:
* commons-dbutils-1.6.jar
*/
public class Demo1 {
/**
* DbUtils 执行 sql 语句 插入数据
*/
@Test
public void testInsert() throws Exception{
// 创建 QueryRunner 对象,传入数据库连接池
QueryRunner queryRunner = new QueryRunner(C3P0Utils.getDataSource());
// 执行 sql 语句插入数据
int num = queryRunner.update("insert into users(username, password) values('lily', '321')");
if (num > 0){
System.out.println("插入数据成功,影响了" + num + "行.");
}
// 执行 sql 语句插入数据,传入参数
// 接收参数的方法定义:update(String sql, Object... params)
// 最后一个参数 Object... 表示是可变参数,是需要传入到参数 1 的 sql 语句中的值;
num = queryRunner.update("insert into users(username, password) values(?, ?)", "lucy", "456");
if (num > 0){
System.out.println("插入数据成功,影响了" + num + "行.");
}
}
/**
* DbUtils 执行 sql 语句 修改数据
*/
@Test
public void testUpdate() throws Exception{
// 创建 QueryRunner 对象,传入数据库连接池
QueryRunner queryRunner = new QueryRunner(C3P0Utils.getDataSource());
// 执行 sql 语句,修改数据
int num = queryRunner.update("update users set username=?, password=? where id=?", "Jack", "789", 24);
if (num > 0){
System.out.println("修改数据成功,影响了" + num + "行.");
}
}
/**
* DbUtils 执行 sql 语句 删除数据
*/
@Test
public void testDelete() throws Exception{
// 创建 QueryRunner 对象,传入 数据库连接池
QueryRunner queryRunner = new QueryRunner(C3P0Utils.getDataSource());
// 执行 sql 语句,删除数据
int num = queryRunner.update("delete from users where id=?", 23);
if (num > 0){
System.out.println("删除数据成功,影响了" + num + "行.");
}
}
/**
* DbUtils 执行 批处理 语句
* 批处理只能执行相同的 sql 语句
*/
@Test
public void testBatch() throws Exception{
// 创建 QueryRunner 对象,传入 数据库连接池
QueryRunner queryRunner = new QueryRunner(C3P0Utils.getDataSource());
// 定义一个 二位数组,作为 批处理语句的 参数
String[][] param = new String[10][]; // 表示循环 10 次,执行 10 次 sql 语句
for (int i = 0; i < param.length; i++) {
param[i] = new String[]{"jerry" + i, "66" + i}; // 给每次执行的 sql 语句中的 ? 赋值
}
// 执行 批处理语句
int[] num = queryRunner.batch("insert into users(username, password) values(?, ?)", param);
}
/**
* DbUtils 执行 sql 语句查询数据
* 使用 ResultSetHandler 接口的匿名内部类方式实现
*/
@Test
public void testSelect1() throws Exception{
// 创建一个 QueryRunner 对象,传入一个数据库连接池
QueryRunner queryRunner = new QueryRunner(C3P0Utils.getDataSource());
// 执行 sql 语句查询数据,并将结果集封装到 list 集合中返回
List<User> list = queryRunner.query("select * from users", new ResultSetHandler<List<User>>() {
// 当 query 方法执行 select 语句后,将结果集以参数的形式传入到 handle 方法中;
@Override
public List<User> handle(ResultSet resultSet) throws SQLException {
// 将 结果集中的数据封装到 list 集合中
List<User> list = new ArrayList<>();
while(resultSet.next()){
User user = new User();
user.setId(resultSet.getInt("id"));
user.setUsername(resultSet.getString("username"));
user.setPassword(resultSet.getString("password"));
list.add(user);
}
// 返回 list 集合
return list;
}
});
// 输出 list 集合中的数据
for (User user : list) {
System.out.println(user);
}
}
/*************************************************
ResultSetHandler 接口定义 select 操作后怎样封装结果集,可以使用下面几个已经实现了该接口的类 更方便的封装结果集:
1、BeanListHandler:该类会自动 将结果集封装到 list 集合中;
2、ArrayHandler:该类适合只获取 1 条记录,把该记录每列的值封装到 object[] 数组中;
如果 sql 语句没有带条件,能够查询到多条记录,则 ArrayHandler 只封装查询到的第一条记录;
3、ArrayListHandler:获取多条数据,先将每条记录的每列值封装到一个 object[] 数组中,然后再将数组封装到一个 list 集合中;
4、ColumnListHandler:获取某一列的数据,并将数据封装到 list 中;
5、MapHandler:适合获取1条记录,把查询到的列名和列值封装到 Map 中;
如果 sql 语句能够查到多条数据,那么 MapHandler 也只会封装第一条数据;
6、KeyedHandler:获取多条记录,把每一条记录封装到一个 Map 中,再把这个 Map 封装到另一个 Map 中,key 为指定的字段值;
7、MapListHandler:获取多条记录,把每条记录封装到一个 Map 中,然后再把这个 Map 封装到 List 集合中;
8、ScalarHandler:适合获取单行单列数据;
*************************************************/
/**
* DbUtils 执行 sql 语句,查询数据
* 1、使用 BeanListHandler 类实现,该类会自动 将结果集封装到 list 集合中
*/
@Test
public void testSelect2() throws Exception{
// 创建 QueryRunner 对象,传入一个 数据库连接池
QueryRunner queryRunner = new QueryRunner(C3P0Utils.getDataSource());
// 执行 SQL 语句查询数据,并将结果集封装到 list 集合中;泛型和参数类型为 Javabean 类;
List<User> list = queryRunner.query("select * from users", new BeanListHandler<User>(User.class));
// 输出 list 集合中的数据
for (User user : list) {
System.out.println(user);
}
// 执行 sql 语句,查询数据,并将结果集封装到 list 集合中,传入参数
// 接收参数的 query 方法定义:query(String sql, ResultSetHandler<T> rsh, Object... params);
// 最后一个参数 Object... 表示是可变参数,是需要传入到参数 1 的 sql 语句中的值;
List<User> list2 = queryRunner.query("select * from users where username=? and password=?", new BeanListHandler<User>(User.class), "rose6", "126");
// 输出 list2 集合中的数据
for (User user : list2) {
System.out.println(user);
}
}
/**
* DbUtils 执行 sql 语句,查询数据
* 2、使用 ArrayHandler 类实现:只取 1 条记录,把该记录每列的值封装到 object[] 数组中
*/
@Test
public void testSelect3() throws Exception{
// 创建 QueryRunner 对象,传入 数据库连接池
QueryRunner queryRunner = new QueryRunner(C3P0Utils.getDataSource());
// 执行 sql 语句,查询数据
// Object[] arr = queryRunner.query("select * from users where id=?", new ArrayHandler(), 3);
// 如果 sql 语句不写条件,则只取第一条记录
Object[] arr = queryRunner.query("select * from users", new ArrayHandler());
// 遍历数组中 每列的值
for (Object obj : arr) {
System.out.print(obj + ",");
}
System.out.println();
}
/**
* DbUtils 执行 sql 语句,查询数据
* 3、使用 ArrayListHandler 类实现:
* 取多条数据,先将每条记录的每列值封装到一个 object[] 数组中,然后再将数组封装到一个 list 集合中
*/
@Test
public void testSelect4() throws Exception{
// 创建 QueryRunner 对象,传入 数据库连接池
QueryRunner queryRunner = new QueryRunner(C3P0Utils.getDataSource());
// 执行 sql 语句,查询数据
List<Object[]> list = queryRunner.query("select * from users", new ArrayListHandler());
// 遍历结果
for (Object[] arr : list) { // list 集合中封装的是 object[] 数组
for (Object obj : arr) { // object[] 数组中封装的是 每条记录的 每列的值
System.out.print(obj + ",");
}
System.out.println();
}
}
/**
* DbUtils 执行 sql 语句,查询数据
* 4、使用 ColumnListHandler 类实现:
* 获取某一列的数据,并封装到 list 集合中;
*/
@Test
public void testSelect5() throws Exception{
// 创建 QueryRunner 对象,传入 数据库连接池
QueryRunner queryRunner = new QueryRunner(C3P0Utils.getDataSource());
// 执行 sql 语句,查询数据
// 不指定列的时候,默认获取第一列的数据
List<Object> list1 = queryRunner.query("select * from users", new ColumnListHandler<Object>());
System.out.println(list1);
// 可以指定列的序号:获取 第2列 的数据
List<Object> list2 = queryRunner.query("select * from users", new ColumnListHandler<Object>(2));
System.out.println(list2);
// 也可以指定列的名字:获取 username 列的数据
List<String> list3 = queryRunner.query("select * from users", new ColumnListHandler<String>("username"));
System.out.println(list3);
}
/**
* DbUtils 执行 sql 语句,查询数据
* 5、使用 MapHandler 类实现:
* 适合获取1条记录,把查询到的列名和列值封装到 Map 中
*/
@Test
public void testSelect6() throws Exception {
// 创建 QueryRunner 对象,传入 数据库连接池
QueryRunner queryRunner = new QueryRunner(C3P0Utils.getDataSource());
// 执行 sql 语句,查询数据;只封装第一条数据
Map<String, Object> map = queryRunner.query("select * from users", new MapHandler());
// 遍历:key 为列名,value 为列值
for (Map.Entry<String, Object> m : map.entrySet()) {
System.out.println(m.getKey() + "=" + m.getValue());
}
}
/**
* DbUtils 执行 sql 语句,查询数据
* 6、使用 KeyedHandler 类实现:
* 获取多条记录,每一条记录封装到一个 Map 中,再把这个 Map 封装到另一个 Map 中,key 为指定的字段值;
*/
@Test
public void testSelect7() throws Exception {
// 创建 QueryRunner 对象,传入 数据库连接池
QueryRunner queryRunner = new QueryRunner(C3P0Utils.getDataSource());
// 执行 sql 语句,查询数据
// 外层 Map 的 key 是第一列的值,所以是 Object 类型(不确定);内层 Map 的 key 是表的列名,所以是 String 类型(列名只能是字符串);
Map<Object, Map<String, Object>> map = queryRunner.query("select * from users", new KeyedHandler<Object>());
// 遍历
for (Map.Entry<Object, Map<String, Object>> mapEntry : map.entrySet()) {
// 外层 Map 的 key 就是 id 列的值
System.out.println("id: " + mapEntry.getValue());
// 外层 Map 的 value,也就是内层 Map,封装的就是 一条记录数据
for (Map.Entry<String, Object> m : mapEntry.getValue().entrySet()) {
// 内层 Map 就是一条记录:key 就是列名,value 就是列值
System.out.println(m.getKey() + "=" + m.getValue());
}
System.out.println("-----------------");
}
}
/**
* DbUtils 执行 sql 语句,查询数据
* 7、使用 MapListHandler 类实现:
* 适合获取多条记录,把每条记录封装到 Map 中,然后再把 Map 封装到 List 集合中;
*/
@Test
public void testSelect8() throws Exception {
// 创建 QueryRunner 对象,传入 数据库连接池
QueryRunner queryRunner = new QueryRunner(C3P0Utils.getDataSource());
// 执行 sql 语句,查询数据;
List<Map<String, Object>> list = queryRunner.query("select * from users", new MapListHandler());
// 遍历:
for (Map<String, Object> map : list) {
for (Map.Entry<String, Object> m : map.entrySet()) {
System.out.println(m.getKey() + "=" + m.getValue());
}
System.out.println("----------------------");
}
}
/**
* DbUtils 执行 sql 语句,查询数据
* 8、使用 ScalarHandler 类实现:
* 适合获取单行单列数据;
*/
@Test
public void testSelect9() throws Exception {
// 创建 QueryRunner 对象,传入 数据库连接池
QueryRunner queryRunner = new QueryRunner(C3P0Utils.getDataSource());
// 执行 sql 语句,查询数据;
// 默认获取 第一行第一列
Object query = queryRunner.query("select * from users", new ScalarHandler<>());
System.out.println(query);
// 获取 第一行第二列
Object query2 = queryRunner.query("select * from users", new ScalarHandler<>(2));
System.out.println(query2);
// 获取 第一行 password 列
Object query3 = queryRunner.query("select * from users", new ScalarHandler<>("password"));
System.out.println(query3);
}
}
其中 C3P0Utils.java:
package com.jdbc.dbutils;
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;
public class C3P0Utils {
/**
* 创建 C3P0 连接池对象(默认加载 src 下的 c3p0-config.xml 配置文件)
*/
private static DataSource dataSource = new ComboPooledDataSource();
/**
* 传出 DataSource 对象
*/
public static DataSource getDataSource() {
return dataSource;
}
/**
* 从连接池中获取一个 数据库连接对象
*/
public static Connection getConnection() {
try {
return dataSource.getConnection();
} catch (SQLException e) {
throw new RuntimeException();
}
}
/**
* 释放资源
*/
public static void release(Connection conn, Statement stmt, ResultSet rs) {
if (rs != null) {
try {
rs.close();
} catch (Exception e) {
e.printStackTrace();
}
rs = null;
}
if (stmt != null) {
try {
stmt.close();
} catch (Exception e) {
e.printStackTrace();
}
stmt = null;
}
if (conn != null) {
try {
conn.close();
} catch (Exception e) {
e.printStackTrace();
}
conn = null;
}
}
}
其中 c3p0-config.xml:
<c3p0-config>
<default-config>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/day17</property>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="user">root</property>
<property name="password">root</property>
<property name="initialPoolSize">3</property>
<property name="maxPoolSize">10</property>
<property name="maxIdleTime">3000</property>
</default-config>
</c3p0-config>
其中 数据库:
其中 User.java:
package com.jdbc.dbutils;
public class User {
private int id;
private String username;
private String password;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
}