> 文章列表 > JDBC03-批处理、连接池、DBUtils、事物、DAO通用方法

JDBC03-批处理、连接池、DBUtils、事物、DAO通用方法

JDBC03-批处理、连接池、DBUtils、事物、DAO通用方法

1. 封装 JDBCUtils 【关闭、得到连接】

1.1 说明

JDBC03-批处理、连接池、DBUtils、事物、DAO通用方法
JDBC03-批处理、连接池、DBUtils、事物、DAO通用方法

1.2 代码实现

工具类 JDBCUtils

package com.hspedu.jdbc.utils;import java.io.FileInputStream;
import java.io.IOException;
import java.sql.*;
import java.util.Properties;
/**
* 这是一个工具类,完成 mysql 的连接和关闭资源
*/
public class JDBCUtils {//定义相关的属性(4 个), 因为只需要一份,因此,我们做出 staticprivate static String user; //用户名private static String password; //密码private static String url; //urlprivate static String driver; //驱动名//在 static 代码块去初始化static {try {Properties properties = new Properties();properties.load(new FileInputStream("src\\\\mysql.properties"));//读取相关的属性值user = properties.getProperty("user");password = properties.getProperty("password");url = properties.getProperty("url");driver = properties.getProperty("driver");} catch (IOException e) {//在实际开发中,我们可以这样处理//1. 将编译异常转成 运行异常//2. 调用者,可以选择捕获该异常,也可以选择默认处理该异常,比较方便. throw new RuntimeException(e);} }//连接数据库, 返回 Connectionpublic static Connection getConnection() {try {return DriverManager.getConnection(url, user, password);} catch (SQLException e) {//1. 将编译异常转成 运行异常//2. 调用者,可以选择捕获该异常,也可以选择默认处理该异常,比较方便. throw new RuntimeException(e);}}//关闭相关资源/*1. ResultSet 结果集2. Statement 或者 PreparedStatement3. Connection4. 如果需要关闭资源,就传入对象,否则传入 null*/public static void close(ResultSet set, Statement statement, Connection connection) {//判断是否为 nulltry {if (set != null) {set.close();}if (statement != null) {statement.close();}if (connection != null) {connection.close();}} catch (SQLException e) {//将编译异常转成运行异常抛出throw new RuntimeException(e);}}
}

测试类

package com.hspedu.jdbc.utils;import org.junit.jupiter.api.Test;
import java.sql.*;/**
* 该类演示如何使用 JDBCUtils 工具类,完成 dml 和 select
*/
public class JDBCUtils_Use {@Testpublic void testSelect() {//1. 得到连接Connection connection = null;//2. 组织一个 sqlString sql = "select * from actor where id = ?";PreparedStatement preparedStatement = null;ResultSet set = null;//3. 创建 PreparedStatement 对象try {connection = JDBCUtils.getConnection();System.out.println(connection.getClass()); //com.mysql.jdbc.JDBC4ConnectionpreparedStatement = connection.prepareStatement(sql);preparedStatement.setInt(1, 5);//给?号赋值//执行, 得到结果集set = preparedStatement.executeQuery();//遍历该结果集while (set.next()) {int id = set.getInt("id");String name = set.getString("name");String sex = set.getString("sex");Date borndate = set.getDate("borndate");String phone = set.getString("phone");System.out.println(id + "\\t" + name + "\\t" + sex + "\\t" + borndate + "\\t" + phone);}} catch (SQLException e) {e.printStackTrace();} finally {//关闭资源JDBCUtils.close(set, preparedStatement, connection);}}@Testpublic void testDML() {//insert , update, delete//1. 得到连接Connection connection = null;//2. 组织一个 sqlString sql = "update actor set name = ? where id = ?";// 测试 delete 和 insert ,自己玩. PreparedStatement preparedStatement = null;//3. 创建 PreparedStatement 对象try {connection = JDBCUtils.getConnection();preparedStatement = connection.prepareStatement(sql);//给占位符赋值preparedStatement.setString(1, "周星驰");preparedStatement.setInt(2, 4);//执行preparedStatement.executeUpdate();} catch (SQLException e) {e.printStackTrace();} finally {//关闭资源JDBCUtils.close(null, preparedStatement, connection);}}
}

2. 事务

2.1 基本介绍

JDBC03-批处理、连接池、DBUtils、事物、DAO通用方法

2.2 应用实例

模拟经典的转账业务
JDBC03-批处理、连接池、DBUtils、事物、DAO通用方法
JDBC03-批处理、连接池、DBUtils、事物、DAO通用方法

2.3 不使用事务可能出现的问题模拟-模拟经典的转账业务

//没有使用事务. 
@Test
public void noTransaction() {//操作转账的业务//1. 得到连接Connection connection = null;//2. 组织一个 sqlString sql = "update account set balance = balance - 100 where id = 1";String sql2 = "update account set balance = balance + 100 where id = 2";PreparedStatement preparedStatement = null;//3. 创建 PreparedStatement 对象try {connection = JDBCUtils.getConnection(); // 在默认情况下,connection 是默认自动提交preparedStatement = connection.prepareStatement(sql);preparedStatement.executeUpdate(); // 执行第 1 条 sqlint i = 1 / 0; //抛出异常preparedStatement = connection.prepareStatement(sql2);preparedStatement.executeUpdate(); // 执行第 3 条 sql} catch (SQLException e) {e.printStackTrace();} finally {//关闭资源JDBCUtils.close(null, preparedStatement, connection);}
}

2.4 使用事务解决上述问题-模拟经典的转账业务

//事务来解决
@Test
public void useTransaction() {//操作转账的业务//1. 得到连接Connection connection = null;//2. 组织一个 sqlString sql = "update account set balance = balance - 100 where id = 1";String sql2 = "update account set balance = balance + 100 where id = 2";PreparedStatement preparedStatement = null;//3. 创建 PreparedStatement 对象try {connection = JDBCUtils.getConnection(); // 在默认情况下,connection 是默认自动提交//将 connection 设置为不自动提交connection.setAutoCommit(false); //开启了事务preparedStatement = connection.prepareStatement(sql);preparedStatement.executeUpdate(); // 执行第 1 条 sqlint i = 1 / 0; //抛出异常preparedStatement = connection.prepareStatement(sql2);preparedStatement.executeUpdate(); // 执行第 3 条 sql//这里提交事务connection.commit();} catch (SQLException e) {//这里我们可以进行回滚,即撤销执行的 SQL//默认回滚到事务开始的状态. System.out.println("执行发生了异常,撤销执行的 sql");try {connection.rollback();} catch (SQLException throwables) {throwables.printStackTrace();}e.printStackTrace();} finally {//关闭资源JDBCUtils.close(null, preparedStatement, connection);}
}

3. 批处理

3.1 基本介绍

JDBC03-批处理、连接池、DBUtils、事物、DAO通用方法

JDBC03-批处理、连接池、DBUtils、事物、DAO通用方法

3.2 应用实例

JDBC03-批处理、连接池、DBUtils、事物、DAO通用方法

特别注意:
1.注意修改配置文件
2.记得关闭事物自动提交(巨坑)

package com.hspedu.jdbc.batch_;import com.hspedu.jdbc.utils.JDBCUtils;
import org.junit.jupiter.api.Test;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;/**
* 演示 java 的批处理
*/
public class Batch_ {//传统方法,添加 5000 条数据到 admin2@Testpublic void noBatch() throws Exception {Connection connection = JDBCUtils.getConnection();String sql = "insert into admin2 values(null, ?, ?)";PreparedStatement preparedStatement = connection.prepareStatement(sql);System.out.println("开始执行");long start = System.currentTimeMillis();//开始时间for (int i = 0; i < 5000; i++) {  //5000 执行preparedStatement.setString(1, "jack" + i);preparedStatement.setString(2, "666");preparedStatement.executeUpdate();}long end = System.currentTimeMillis();System.out.println("传统的方式 耗时=" + (end - start));//传统的方式 耗时=10702//关闭连接JDBCUtils.close(null, preparedStatement, connection);}//使用批量方式添加数据@Testpublic void batch() throws Exception {Connection connection = JDBCUtils.getConnection();connection.setAutoCommit(false);String sql = "insert into admin2 values(null, ?, ?)";PreparedStatement preparedStatement = connection.prepareStatement(sql);System.out.println("开始执行");long start = System.currentTimeMillis();//开始时间for (int i = 0; i < 5000; i++) {//5000 执行preparedStatement.setString(1, "jack" + i);preparedStatement.setString(2, "666");//将 sql 语句加入到批处理包中 -> 看源码/*//1. //第一就创建 ArrayList - elementData => Object[]//2. elementData => Object[] 就会存放我们预处理的 sql 语句//3. 当 elementData 满后,就按照 1.5 扩容//4. 当添加到指定的值后,就 executeBatch//5. 批量处理会减少我们发送 sql 语句的网络开销,而且减少编译次数,因此效率提高public void addBatch() throws SQLException {synchronized(this.checkClosed().getConnectionMutex()) {if (this.batchedArgs == null) {this.batchedArgs = new ArrayList();}for(int i = 0; i < this.parameterValues.length; ++i) {this.checkAllParametersSet(this.parameterValues[i], this.parameterStreams[i], i);}this.batchedArgs.add(new PreparedStatement.BatchParams(this.parameterValues, this.parameterStreams, this.isStream, this.streamLengths, this.isNull));}}*/preparedStatement.addBatch();//当有 1000 条记录时,在批量执行if((i + 1) % 1000 == 0) {//满 1000 条 sqlpreparedStatement.executeBatch();//清空一把preparedStatement.clearBatch();}}long end = System.currentTimeMillis();connection.commit();System.out.println("批量方式 耗时=" + (end - start));//批量方式 耗时=108//关闭连接JDBCUtils.close(null, preparedStatement, connection);}
}

4. 数据库连接池

4.1 五k 次连接数据库问题

JDBC03-批处理、连接池、DBUtils、事物、DAO通用方法

package com.hspedu.jdbc.datasource;import com.hspedu.jdbc.utils.JDBCUtils;
import org.junit.jupiter.api.Test;
import java.sql.Connection;public class ConQuestion {//代码 连接 mysql 5000 次@Testpublic void testCon() {//看看连接-关闭 connection 会耗用多久long start = System.currentTimeMillis();System.out.println("开始连接.....");for (int i = 0; i < 5000; i++) {//使用传统的 jdbc 方式,得到连接Connection connection = JDBCUtils.getConnection();//做一些工作,比如得到 PreparedStatement ,发送 sql//.......... //关闭JDBCUtils.close(null, null, connection);}long end = System.currentTimeMillis();System.out.println("传统方式 5000 次 耗时=" + (end - start));//传统方式 5000 次 耗时=7099}
}

4.2 传统获取 Connection 问题分析

JDBC03-批处理、连接池、DBUtils、事物、DAO通用方法

连接示意图
JDBC03-批处理、连接池、DBUtils、事物、DAO通用方法

JDBC03-批处理、连接池、DBUtils、事物、DAO通用方法
连接池示意图
JDBC03-批处理、连接池、DBUtils、事物、DAO通用方法

4.3 数据库连接池种类

JDBC03-批处理、连接池、DBUtils、事物、DAO通用方法

4.3.1 C3P0

继承关系图
JDBC03-批处理、连接池、DBUtils、事物、DAO通用方法

厂家必须实现该接口

JDBC03-批处理、连接池、DBUtils、事物、DAO通用方法
最大连接数和初始化连接数的区别
JDBC03-批处理、连接池、DBUtils、事物、DAO通用方法

前期准备:先导入jar包
JDBC03-批处理、连接池、DBUtils、事物、DAO通用方法

应用实例
JDBC03-批处理、连接池、DBUtils、事物、DAO通用方法
1)方式1

package com.hspedu.jdbc.datasource;import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.junit.jupiter.api.Test;
import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;/**
* 演示 c3p0 的使用
*///方式 1: 相关参数,在程序中指定 user, url , password 等
@Test
public void testC3P0_01() throws Exception {//1. 创建一个数据源对象(相当于连接池)ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();//2. 通过配置文件 mysql.properties 获取相关连接的信息Properties properties = new Properties();properties.load(new FileInputStream("src\\\\mysql.properties"));//读取相关的属性值String user = properties.getProperty("user");String password = properties.getProperty("password");String url = properties.getProperty("url");String driver = properties.getProperty("driver");//给数据源 comboPooledDataSource 设置相关的参数//注意:连接管理是由 comboPooledDataSource 来管理comboPooledDataSource.setDriverClass(driver);comboPooledDataSource.setJdbcUrl(url);comboPooledDataSource.setUser(user);comboPooledDataSource.setPassword(password);//设置初始化连接数comboPooledDataSource.setInitialPoolSize(10);//最大连接数  区别如上图comboPooledDataSource.setMaxPoolSize(50);//测试连接池的效率, 测试对 mysql 5000 次操作long start = System.currentTimeMillis();for (int i = 0; i < 5000; i++) {Connection connection = comboPooledDataSource.getConnection(); //这个方法就是从 DataSource 接口实现的//System.out.println("连接 OK");connection.close();}long end = System.currentTimeMillis();//c3p0 5000 连接 mysql 耗时=391System.out.println("c3p0 5000 连接 mysql 耗时=" + (end - start));
}

2)方式2
需要先添加配置文件:c3p0-config.xml

<c3p0-config>
<!-- 定义名字 --><named-config name="my_c3p0"> 
<!-- 驱动类 --><property name="driverClass">com.mysql.jdbc.Driver</property><!-- url--><property name="jdbcUrl">jdbc:mysql://127.0.0.1:3306/t1</property><!-- 用户名 --><property name="user">root</property><!-- 密码 --><property name="password">root</property><!-- 每次增长的连接数--><property name="acquireIncrement">5</property><!-- 初始的连接数 --><property name="initialPoolSize">10</property><!-- 最小连接数 --><property name="minPoolSize">5</property><!-- 最大连接数 --><property name="maxPoolSize">50</property><!-- 可连接的最多的命令对象数 --><property name="maxStatements">5</property> <!-- 每个连接对象可连接的最多的命令对象数 --><property name="maxStatementsPerConnection">2</property></named-config>
</c3p0-config>

说明:
JDBC03-批处理、连接池、DBUtils、事物、DAO通用方法

//第二种方式 使用配置文件模板来完成
//1. 将 c3p0 提供的 c3p0.config.xml 拷贝到 src 目录下
//2. 该文件指定了连接数据库和连接池的相关参数@Test
public void testC3P0_02() throws SQLException {ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource("hsp_edu");//测试 5000 次连接 mysqllong start = System.currentTimeMillis();System.out.println("开始执行....");for (int i = 0; i < 500000; i++) {Connection connection = comboPooledDataSource.getConnection();//System.out.println("连接 OK~");connection.close();}long end = System.currentTimeMillis();//c3p0 的第二种方式 耗时=413System.out.println("c3p0 的第二种方式(500000) 耗时=" + (end - start));//1917
}

4.3.2 Druid(德鲁伊)

JDBC03-批处理、连接池、DBUtils、事物、DAO通用方法
先引入jar包和配置文件
druid.properties

#key=value
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/t1?rewriteBatchedStatements=true
#url=jdbc:mysql://localhost:3306/girls
username=root
password=root
#initial connection Size
initialSize=10
#min idle connecton size  类似最小连接数
minIdle=5
#max active connection size
maxActive=20
#max wait time (5000 mil seconds)  等待最大时长为5秒
maxWait=5000
@Test
public void testDruid() throws Exception {//1. 加入 Druid jar 包//2. 加入 配置文件 druid.properties , 将该文件拷贝项目的 src 目录//3. 创建 Properties 对象, 读取配置文件Properties properties = new Properties();properties.load(new FileInputStream("src\\\\druid.properties"));//4. 创建一个指定参数的数据库连接池, Druid 连接池DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);long start = System.currentTimeMillis();for (int i = 0; i < 500000; i++) {Connection connection = dataSource.getConnection();System.out.println(connection.getClass());//System.out.println("连接成功!");connection.close();}long end = System.currentTimeMillis();//druid 连接池 操作 5000 耗时=412System.out.println("druid 连接池 操作 500000 耗时=" + (end - start));//539
}

4.4 将 JDBCUtils 工具类改成 Druid(德鲁伊)实现

JDBC03-批处理、连接池、DBUtils、事物、DAO通用方法

/**
* 基于 druid 数据库连接池的工具类
*/
public class JDBCUtilsByDruid {private static DataSource ds;//在静态代码块完成 ds 初始化static {Properties properties = new Properties();try {properties.load(new FileInputStream("src\\\\druid.properties"));ds = DruidDataSourceFactory.createDataSource(properties);} catch (Exception e) {e.printStackTrace();}}//编写 getConnection 方法public static Connection getConnection() throws SQLException {return ds.getConnection();}//关闭连接, 老师再次强调: 在数据库连接池技术中,close 不是真的断掉连接//而是把使用的 Connection 对象放回连接池public static void close(ResultSet resultSet, Statement statement, Connection connection) {try {if (resultSet != null) {resultSet.close();}if (statement != null) {statement.close();}if (connection != null) {connection.close();}} catch (SQLException e) {throw new RuntimeException(e);}}
}

测试类

@SuppressWarnings({"all"})
public class JDBCUtilsByDruid_USE {@Testpublic void testSelect() {System.out.println("使用 druid 方式完成");//1. 得到连接Connection connection = null;//2. 组织一个 sqlString sql = "select * from actor where id >= ?";PreparedStatement preparedStatement = null;ResultSet set = null;//3. 创建 PreparedStatement 对象try {connection = JDBCUtilsByDruid.getConnection();System.out.println(connection.getClass());//运行类型 com.alibaba.druid.pool.DruidPooledConnectionpreparedStatement = connection.prepareStatement(sql);preparedStatement.setInt(1, 1);//给?号赋值//执行, 得到结果集set = preparedStatement.executeQuery();//遍历该结果集while (set.next()) {int id = set.getInt("id");String name = set.getString("name");//getName()String sex = set.getString("sex");//getSex()Date borndate = set.getDate("borndate");String phone = set.getString("phone");System.out.println(id + "\\t" + name + "\\t" + sex + "\\t" + borndate + "\\t" + phone);}} catch (SQLException e) {e.printStackTrace();} finally {//关闭资源JDBCUtilsByDruid.close(set, preparedStatement, connection);}}
}

5. Apache—DBUtils

5.1 先分析一个问题

JDBC03-批处理、连接池、DBUtils、事物、DAO通用方法

5.2 解决方案

JDBC03-批处理、连接池、DBUtils、事物、DAO通用方法

5.3 用自己的土方法来解决

1)先创建一个类,用于映射

package com.pojo;/*** 该类用于和数据库数据进行绑定*/
public class Actor {private int id;private String name;private String sex;private String borndate;private String phone;public Actor() {//一定要提供,将来反射要用}public Actor(int id, String name, String sex, String borndate, String phone) {this.id = id;this.name = name;this.sex = sex;this.borndate = borndate;this.phone = phone;}public int getId() {return id;}public String getName() {return name;}public String getSex() {return sex;}public String getBorndate() {return borndate;}public String getPhone() {return phone;}@Overridepublic String toString() {return "Actor{" +"id=" + id +", name='" + name + '\\'' +", sex='" + sex + '\\'' +", borndate='" + borndate + '\\'' +", phone='" + phone + '\\'' +'}';}public void setId(int id) {this.id = id;}public void setName(String name) {this.name = name;}public void setSex(String sex) {this.sex = sex;}public void setBorndate(String borndate) {this.borndate = borndate;}public void setPhone(String phone) {this.phone = phone;}
}

注意事项:
1.必须提供无参构造和set方法,DBUtil框架使用反射时需要使用

2)测试方法

//使用老师的土方法来解决 ResultSet =封装=> Arraylist
@Test
public ArrayList<Actor> testSelectToArrayList() {System.out.println("使用 druid 方式完成");//1. 得到连接Connection connection = null;//2. 组织一个 sqlString sql = "select * from actor where id >= ?";PreparedStatement preparedStatement = null;ResultSet set = null;ArrayList<Actor> list = new ArrayList<>();//创建 ArrayList 对象,存放 actor 对象//3. 创建 PreparedStatement 对象try {connection = JDBCUtilsByDruid.getConnection();System.out.println(connection.getClass());//运行类型 com.alibaba.druid.pool.DruidPooledConnectionpreparedStatement = connection.prepareStatement(sql);preparedStatement.setInt(1, 1);//给?号赋值//执行, 得到结果集set = preparedStatement.executeQuery();//遍历该结果集while (set.next()) {int id = set.getInt("id");String name = set.getString("name");//getName()String sex = set.getString("sex");//getSex()Date borndate = set.getDate("borndate");String phone = set.getString("phone");//把得到的 resultset 的记录,封装到 Actor 对象,放入到 list 集合list.add(new Actor(id, name, sex, borndate, phone));}System.out.println("list 集合数据=" + list);for(Actor actor : list) {System.out.println("id=" + actor.getId() + "\\t" + actor.getName());}} catch (SQLException e) {e.printStackTrace();} finally {//关闭资源JDBCUtilsByDruid.close(set, preparedStatement, connection);}//因为 ArrayList 和 connection 没有任何关联,所以该集合可以复用. return list;
}

5.4 DBUtils引入和基本介绍

JDBC03-批处理、连接池、DBUtils、事物、DAO通用方法

5.4.1 应用实例

JDBC03-批处理、连接池、DBUtils、事物、DAO通用方法
入门案例:

//使用 apache-DBUtils 工具类 + druid 完成对表的 crud 操作
@Test
public void testQueryMany() throws SQLException { //返回结果是多行的情况//1. 得到 连接 (druid)Connection connection = JDBCUtilsByDruid.getConnection();//2. 使用 DBUtils 类和接口 , 先引入 DBUtils 相关的 jar , 加入到本 Project//3. 创建 QueryRunnerQueryRunner queryRunner = new QueryRunner();//4. 就可以执行相关的方法,返回 ArrayList 结果集//String sql = "select * from actor where id >= ?";// 注意: sql 语句也可以查询部分列String sql = "select id, name from actor where id >= ?";// 解读//(1) query 方法就是执行 sql 语句,得到 resultset ---封装到 --> ArrayList 集合中//(2) 返回集合//(3) connection: 连接//(4) sql : 执行的 sql 语句//(5) new BeanListHandler<>(Actor.class): 在将 resultset -> Actor 对象 -> 封装到 ArrayList// 底层使用反射机制 去获取 Actor 类的属性,然后进行封装//(6) 1 就是给 sql 语句中的? 赋值,可以有多个值,因为是可变参数 Object... params//(7) 底层得到的 resultset ,会在 query 关闭, 关闭 PreparedStatment/*** 分析 queryRunner.query 方法:* public <T> T query(Connection conn, String sql, ResultSetHandler<T> rsh, Object... params) throws SQLException {* 	PreparedStatement stmt = null;//定义 PreparedStatement* 	ResultSet rs = null;//接收返回的 ResultSet* 	Object result = null;//返回 ArrayList** 	try {* 		stmt = this.prepareStatement(conn, sql);//创建 PreparedStatement* 		this.fillStatement(stmt, params);//对 sql 进行 ? 赋值* 		rs = this.wrap(stmt.executeQuery());//执行 sql,返回 resultset* 		result = rsh.handle(rs);//返回的 resultset --> arrayList[result] [使用到反射,对传入 class 对象处理]* 	} catch (SQLException var33) {* 		this.rethrow(var33, sql, params);* 	} finally {* 		try {* 			this.close(rs);//关闭 resultset*   	} finally {* 			this.close((Statement)stmt);//关闭 preparedstatement 对象* 		}* 	}* 	return result;* }*/List<Actor> list =queryRunner.query(connection, sql, new BeanListHandler<>(Actor.class), 1);System.out.println("输出集合的信息");for (Actor actor : list) {System.out.print(actor);}//释放资源JDBCUtilsByDruid.close(null, null, connection);
}

5.4.2 ResultSetHandler的种类

1)返回的结果是单行记录(单个对象)

//演示 apache-dbutils + druid 
//完成 返回的结果是单行记录(单个对象)
@Test
public void testQuerySingle() throws SQLException {//1. 得到 连接 (druid)Connection connection = JDBCUtilsByDruid.getConnection();//2. 使用 DBUtils 类和接口 , 先引入 DBUtils 相关的 jar , 加入到本 Project//3. 创建 QueryRunnerQueryRunner queryRunner = new QueryRunner();//4. 就可以执行相关的方法,返回单个对象String sql = "select * from actor where id = ?";// 解读// 因为我们返回的单行记录<--->单个对象 , 使用的 Hander 是 BeanHandlerActor actor = queryRunner.query(connection, sql, new BeanHandler<>(Actor.class), 10);System.out.println(actor);// 释放资源JDBCUtilsByDruid.close(null, null, connection);
}

2)完成查询结果是单行单列-返回的就是 object

//演示 apache-dbutils + druid 
//完成查询结果是单行单列-返回的就是 object
@Test
public void testScalar() throws SQLException {//1. 得到 连接 (druid)Connection connection = JDBCUtilsByDruid.getConnection();//2. 使用 DBUtils 类和接口 , 先引入 DBUtils 相关的 jar , 加入到本 Project//3. 创建 QueryRunnerQueryRunner queryRunner = new QueryRunner();//4. 就可以执行相关的方法,返回单行单列 , 返回的就是 ObjectString sql = "select name from actor where id = ?";//解读: 因为返回的是一个对象, 使用的 handler 就是 ScalarHandlerObject obj = queryRunner.query(connection, sql, new ScalarHandler(), 4);System.out.println(obj);// 释放资源JDBCUtilsByDruid.close(null, null, connection);
}

5.4.3 DButils的dml操作

//演示 apache-dbutils + druid 
//完成 dml (update, insert ,delete)
@Test
public void testDML() throws SQLException {//1. 得到 连接 (druid)Connection connection = JDBCUtilsByDruid.getConnection();//2. 使用 DBUtils 类和接口 , 先引入 DBUtils 相关的 jar , 加入到本 Project//3. 创建 QueryRunnerQueryRunner queryRunner = new QueryRunner();//4. 这里组织 sql 完成 update, insert delete//String sql = "update actor set name = ? where id = ?";//String sql = "insert into actor values(null, ?, ?, ?, ?)";String sql = "delete from actor where id = ?";//解读//(1) 执行 dml 操作是 queryRunner.update()//(2) 返回的值是受影响的行数 (affected: 受影响)//int affectedRow = queryRunner.update(connection, sql, "林青霞", "女", "1966-10-10", "116");int affectedRow = queryRunner.update(connection, sql, 1000 );System.out.println(affectedRow > 0 ? "执行成功" : "执行没有影响到表");// 释放资源JDBCUtilsByDruid.close(null, null, connection);
}

5.5 表和 JavaBean 的类型映射关系

JDBC03-批处理、连接池、DBUtils、事物、DAO通用方法

6. DAO 和增删改查通用方法-BasicDao

6.1 问题引入说明

JDBC03-批处理、连接池、DBUtils、事物、DAO通用方法
架构图
JDBC03-批处理、连接池、DBUtils、事物、DAO通用方法

6.2 DAO说明

JDBC03-批处理、连接池、DBUtils、事物、DAO通用方法

6.3 应用实例

JDBC03-批处理、连接池、DBUtils、事物、DAO通用方法
javaBean

/**
* Actor 对象和 actor 表的记录对应
*/
public class Actor { //Javabean, POJO, Domain 对象private Integer id;private String name;private String sex;private Date borndate;private String phone;public Actor() { //一定要给一个无参构造器[反射需要]}public Actor(Integer id, String name, String sex, Date borndate, String phone) {this.id = id;this.name = name;this.sex = sex;this.borndate = borndate;this.phone = phone;}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getSex() {return sex;}public void setSex(String sex) {this.sex = sex;}public Date getBorndate() {return borndate;}public void setBorndate(Date borndate) {this.borndate = borndate;}public String getPhone() {return phone;}public void setPhone(String phone) {this.phone = phone;}@Overridepublic String toString() {return "\\nActor{" +"id=" + id +", name='" + name + '\\'' +", sex='" + sex + '\\'' +", borndate=" + borndate +", phone='" + phone + '\\'' +'}';}
}

utils:工具类

/**
* 基于 druid 数据库连接池的工具类
*/
public class JDBCUtilsByDruid {private static DataSource ds;//在静态代码块完成 ds 初始化static {Properties properties = new Properties();try {properties.load(new FileInputStream("src\\\\druid.properties"));ds = DruidDataSourceFactory.createDataSource(properties);} catch (Exception e) {e.printStackTrace();}}//编写 getConnection 方法public static Connection getConnection() throws SQLException {return ds.getConnection();}//关闭连接, 老师再次强调: 在数据库连接池技术中,close 不是真的断掉连接//而是把使用的 Connection 对象放回连接池public static void close(ResultSet resultSet, Statement statement, Connection connection) {try {if (resultSet != null) {resultSet.close();}if (statement != null) {statement.close();}if (connection != null) {connection.close();}} catch (SQLException e) {throw new RuntimeException(e);}}
}

BasicDAO

/**
* 开发 BasicDAO , 是其他 DAO 的父类, 使用到 apache-dbutils
*/
public class BasicDAO<T> { //泛型指定具体类型private QueryRunner qr = new QueryRunner();//开发通用的 dml 方法, 针对任意的表public int update(String sql, Object... parameters) {Connection connection = null;try {connection = JDBCUtilsByDruid.getConnection();int update = qr.update(connection, sql, parameters);return update;} catch (SQLException e) {throw new RuntimeException(e); //将编译异常->运行异常 ,抛出} finally {JDBCUtilsByDruid.close(null, null, connection);}}//返回多个对象(即查询的结果是多行), 针对任意表/**** @param sql sql 语句,可以有 ?* @param clazz 传入一个类的 Class 对象 比如 Actor.class* @param parameters 传入 ? 的具体的值,可以是多个* @return 根据 Actor.class 返回对应的 ArrayList 集合*/public List<T> queryMulti(String sql, Class<T> clazz, Object... parameters) {Connection connection = null;try {connection = JDBCUtilsByDruid.getConnection();return qr.query(connection, sql, new BeanListHandler<T>(clazz), parameters);} catch (SQLException e) {throw new RuntimeException(e); //将编译异常->运行异常 ,抛出} finally {JDBCUtilsByDruid.close(null, null, connection);}}//查询单行结果 的通用方法public T querySingle(String sql, Class<T> clazz, Object... parameters) {Connection connection = null;try {connection = JDBCUtilsByDruid.getConnection();return qr.query(connection, sql, new BeanHandler<T>(clazz), parameters);} catch (SQLException e) {throw new RuntimeException(e); //将编译异常->运行异常 ,抛出} finally {JDBCUtilsByDruid.close(null, null, connection);}}//查询单行单列的方法,即返回单值的方法public Object queryScalar(String sql, Object... parameters) {Connection connection = null;try {connection = JDBCUtilsByDruid.getConnection();return qr.query(connection, sql, new ScalarHandler(), parameters);} catch (SQLException e) {throw new RuntimeException(e); //将编译异常->运行异常 ,抛出} finally {JDBCUtilsByDruid.close(null, null, connection);}}
}

ActorDAO

public class ActorDAO extends BasicDAO<Actor> {//1. 就有 BasicDAO 的方法//2. 根据业务需求,可以编写特有的方法. 
}

测试类

//测试 ActorDAO 对 actor 表 crud 操作
@Test
public void testActorDAO() {ActorDAO actorDAO = new ActorDAO();//1. 查询List<Actor> actors = actorDAO.queryMulti("select * from actor where id >= ?", Actor.class, 1);System.out.println("===查询结果===");for (Actor actor : actors) {System.out.println(actor);}//2. 查询单行记录Actor actor = actorDAO.querySingle("select * from actor where id = ?", Actor.class, 6);System.out.println("====查询单行结果====");System.out.println(actor);//3. 查询单行单列Object o = actorDAO.queryScalar("select name from actor where id = ?", 6);System.out.println("====查询单行单列值===");System.out.println(o);//4. dml 操作 insert ,update, deleteint update = actorDAO.update("insert into actor values(null, ?, ?, ?, ?)", "张无忌", "男", "2000-11-11", "999");System.out.println(update > 0 ? "执行成功" : "执行没有影响表");
}