JDBC Apache—DBUtils 详解(通俗易懂)

JDBC Apache—DBUtils 详解(通俗易懂)本文介绍了 ApacheDBUtil 工具类在 JDBC 中的使用 包括其引入背景 传统 ResultSet 的不足 如何通过创建 JavaBean 类改善数据管理和复用 以及 DBUtils 在查询 DQL

大家好,欢迎来到IT知识分享网。

目录

一、前言

二、Apache—DBUtils的引入

        1.传统使用ResultSet的缺点 : 

        2.改进方法 : 

        3.改进方法的模拟实现 : 

三、Apache—DBUtils的使用

        1.基本介绍 : 

        2.准备工作 : 

        3.DBUtils查询(DQL) : 

        4.query方法源码分析 : 

        5.DBUtils处理(DML) : 

四、总结


一、前言

  • 第六节内容,up打算和大家分享一下JDBC——ApacheDBUtils相关的内容。
  • 注意事项——代码中的注释也很重要;不要眼高手低;点击文章的侧边栏目录或者文章开头的目录可以进行跳转。
  • 良工不示人以朴,所有文章都会适时补充完善。大家如果有问题都可以在评论区进行交流或者私信up。 感谢阅读!

二、Apache—DBUtils的引入

        1.传统使用ResultSet的缺点 : 

        返回的结果集ResultSet与Connection是关联的,当调用Connection的close方法关闭连接后(放回连接池),ResultSet对象就不能用了。那么,如果出现“要求结果集复用”的需求,显然是办不到的。PS : 如果在关闭连接后仍调用ResultSet,会报异常,如下图所示 : 

JDBC Apache—DBUtils 详解(通俗易懂)

        就算是先用完ResultSet,再关闭Connection,ResultSet也只是使用了一次,这种对结果集的使用方式显然不利于数据的管理(说没就没)。

        传统使用ResultSet结果集的过程中,也让人感到不爽,如下图所示:

JDBC Apache—DBUtils 详解(通俗易懂)

        我们只能使用固定的格式getXxx来获取表中对应的字段,不但容易在传入形参时出纰漏,而且getInt,getString等也不符合我们“见名知意”的原则。 

        2.改进方法 : 

        之前在JDBC API详解中,我们提到——ResultSet在使用过程中,底层实际是将表中的记录存放在了ArrayLIst集合中。而我们知道,ArrayList底层其实就是一个Object类型的数组elementData。既然如此,我们为什么不把ResultSet结果集中的记录取出来,专门放到一个存放表记录的ArrayList集合中去呢?

        于是,在这种念头的鼓动下,我们想出了以下的牛逼方法(不是我想出来的😂)——

创造一个Java类用于对应一张表,该类中所有的属性对应表中的所有字段,即该类的每个对象都表示了表中的一条记录查询到表中有几条记录,就创建几个该类的实例,不同实例的属性可以自行设置。这样一来,我们只需要将该类的对象存放在ArrayList集合中,就实现了数据的“迁移”,结果集中的数据也得以复用。

        以上,这样的一个类我们称为POJO, 或者Domain,或者一个你早已听过的名字——JavaBean类。

        Apache—DBUtils就是为实现这种需求而诞生的一个工具类,它可以完美解决以上的问题。

        3.改进方法的模拟实现 : 

                在使用Apache—DBUtils工具类之前,我们先简单模拟一下该方法。遵循上文“改进方法”中的思想。我们试着来查询fruit表,fruit表如下 : 

JDBC Apache—DBUtils 详解(通俗易懂)

                Fruit的JavaBean类如下 : 

package apache_dbutils; / MySQL的字段类型与JavaBean类属性的对应关系———— (1) 数值型——>包装类(允许为null) (2) 字符串型——>String类 (3) 日期类型——>Date类 */ public class Fruit { private Integer id; private String name; private Integer sweetness; public Fruit() { } public Fruit(Integer id, String name, Integer sweetness) { this.id = id; this.name = name; this.sweetness = sweetness; } 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 Integer getSweetness() { return sweetness; } public void setSweetness(Integer sweetness) { this.sweetness = sweetness; } @Override public String toString() { return "Fruit{" + "id=" + id + ", name='" + name + '\'' + ", sweetness=" + sweetness + '}'; } } 

                接着我们在测试类中试着将Fruit类对象封装到ArrayList集合中,up以Advanced_Demo类为演示类,代码如下 : 

package apache_dbutils; import connection_pool.druid.JDBCUtilsDruid; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; / * @author : Cyan_RA9 * @version : 21.0 */ public class Advanced_Demo { public static void main(String[] args) { //JDBC核心四部曲 //1.注册驱动(底层根据druid.properties配置文件自动注册了驱动) //Class.forName("com.mysql.cj.jdbc.Driver"); //2.获取连接 Connection connection = null; //3.执行SQL PreparedStatement preparedStatement = null; ResultSet resultSet = null; ArrayList<Fruit> fruitArrayList = new ArrayList<>(); String sql = "SELECT * FROM fruit " + "WHERE `id` >= ?;"; try { connection = JDBCUtilsDruid.getConnection(); preparedStatement = connection.prepareStatement(sql); preparedStatement.setInt(1, 0); resultSet = preparedStatement.executeQuery(); while (resultSet.next()) { int id = resultSet.getInt("id"); String name = resultSet.getString("name"); int sweetness = resultSet.getInt("sweetness"); fruitArrayList.add(new Fruit(id, name, sweetness)); } } catch (SQLException e) { throw new RuntimeException(e); } finally { //4.释放资源 JDBCUtilsDruid.close(resultSet, preparedStatement, connection); } //关闭Connection后,轻松调用集合 System.out.println("List = " + fruitArrayList); System.out.println("==================================="); for (int i = 0; i < fruitArrayList.toArray().length; i++) { System.out.print("id = " + fruitArrayList.get(i).getId()); System.out.print("\tname = " + fruitArrayList.get(i).getName()); System.out.println(); } /* 在某些情况下,我们甚至可以返回该集合其他调用者使用。 eg : return fruitArrayList; */ } } 

                运行结果 : 

JDBC Apache—DBUtils 详解(通俗易懂)


三、Apache—DBUtils的使用

        1.基本介绍 : 

        commons-dbutils是Apache组织提供的一个开源的JDBC工具类库,它是对JDBC的封装,使用dbutils能极大简化JDBC编程的工作量。

        dbutils中常用的类和接口如下——

  • QueryRunner类 : 该类封装了SQL的执行,并且是线程安全的;可以实现增删查改,并且支持批处理。
  • ResultSetHandler接口 : 该接口用于处理java.sql.ResultSet,将数据按照要求转换为另一种格式。常见实现类如下 :         
    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 : 将结果集中的一列映射为一个Object对象,适用于返回单行单列的情况。

        2.准备工作 : 

                先去谷歌搜一下commons-dbutils-jar,进入官网下载Apache_DBUtils的jar包,如下图所示 : 

JDBC Apache—DBUtils 详解(通俗易懂)

                注意要选择Binaries,而不是Source,否则你下载的文件中没有jar包。
                接着还是老规矩,将jar包复制到IDEA中存放jar包的目录下,然后导入当前项目,如下图所示 : 

JDBC Apache—DBUtils 详解(通俗易懂)

        3.DBUtils查询(DQL) : 

                仍然操作fruit表,如下所示 : 

JDBC Apache—DBUtils 详解(通俗易懂)

                up以ApacheDBUtils_Demo1类为演示类,代码如下 : (注意看注释)

package apache_dbutils; import connection_pool.druid.JDBCUtilsDruid; import org.apache.commons.dbutils.QueryRunner; import org.apache.commons.dbutils.handlers.BeanListHandler; import java.sql.Connection; import java.sql.SQLException; import java.util.List; / * @author : Cyan_RA9 * @version : 21.0 */ public class ApacheDBUtils_Demo1 { public static void main(String[] args) throws SQLException { //核心四部曲 //1.注册驱动(根据druid.properties配置文件自动注册) //Class.forName("com.mysql.cj.jdbc.Driver"); //2.获取连接 Connection connection = null; connection = JDBCUtilsDruid.getConnection(); //3.执行SQL QueryRunner queryRunner = new QueryRunner(); String sql = "SELECT * FROM fruit WHERE `id` >= ?;"; List<Fruit> query = queryRunner.query(connection, sql, new BeanListHandler<>(Fruit.class), 2); /* query方法负责执行SQL, 并将得到的结果集封装到ArrayList集合中, 然后返回; PS : 底层得到的ResultSet结果集以及PreparedStatement会在query方法中自动关闭。 方法参数解读———— (1)connection : 当前使用的连接 (2)sql : 需要被执行的SQL (3)new BeanListHandler<>(Fruit.class) : 底层通过反射机制获取到Fruit类的信息; 将ResultSet结果集中的每一条记录都封装到一个Fruit对象中,最后将这些对象 封装到ArrayList集合中。 (4)2 : 可变参数,传给sql中的? */ System.out.println("query = " + query); //4.释放资源 JDBCUtilsDruid.close(null, null, connection); } } 

                运行结果 : 

JDBC Apache—DBUtils 详解(通俗易懂)

        4.query方法源码分析 : 

                我们在query方法处下一个断点,如下图所示 : 

JDBC Apache—DBUtils 详解(通俗易懂)

                接着进入Debug。我们先跳入new BeanListHandler<>(Fruit.class)看看,如下所示 :    

JDBC Apache—DBUtils 详解(通俗易懂)

                继续,我们回去,跳入query方法,如下 : 

JDBC Apache—DBUtils 详解(通俗易懂)

                首次跳入其实是对我们可变参数中的2进行装箱,不管他。重新跳入query,如下 : 

JDBC Apache—DBUtils 详解(通俗易懂)

                经典“包皮”结构,可以看到,我们传入的四个形参都历历在目,并且可以直观的看到最后的可变参数。 但是,这个”this.query(…)”,又是在干嘛呢?不着急,我们可以发现,新调用的query方法无非就是多传入了一个false布尔变量而已。直接跳进去看看,如下图所示 : 

JDBC Apache—DBUtils 详解(通俗易懂)

                我们继续往下看,最下面的else语句才是真正要完成执行SQL的操作滴。如所示 : 

 else { PreparedStatement stmt = null; ResultSet rs = null; T result = null; try { stmt = this.prepareStatement(conn, sql); this.fillStatement(stmt, params); rs = this.wrap(stmt.executeQuery()); result = rsh.handle(rs); } catch (SQLException var33) { this.rethrow(var33, sql, params); } finally { try { this.close(rs); } finally { this.close(stmt); if (closeConn) { this.close(conn); } } } return result; }

                噢,我们心心念念已久的PreparedStatement和ResultSet总算出现辽。可以看到,源码中也是先将对象置为null,之后才初始化的。值得一提的是这个result,直接告诉你结论,这个result就是query方法最终要返回的ArrayList类型的集合。
                继续,这里的prepareStatement方法传入了conn和sql两个实参,其实追进去会发现还是原来那一套——通过连接来获取prepareStatement对象,如下图所示 : 

JDBC Apache—DBUtils 详解(通俗易懂)

                而fillStatement就是用你传入的可变参数来给sql中的?赋值

JDBC Apache—DBUtils 详解(通俗易懂)

                再往下就是通过PreparedStatement对象来执行sql了,此处返回的是结果集。

JDBC Apache—DBUtils 详解(通俗易懂)

                紧接着是handle方法执行,可以肯定的是,handle方法最终返回的一定是ArrayList类型的对象。 我们追进去handle方法看看,如下图所示 : 

JDBC Apache—DBUtils 详解(通俗易懂)

                又是经典包皮结构。别急,我们的目的很明确——找到return ArrayList的语句。继续往下追,如下图所示 : 

JDBC Apache—DBUtils 详解(通俗易懂)

                双层包皮结构?再往下追!如下 : 

JDBC Apache—DBUtils 详解(通俗易懂)

JDBC Apache—DBUtils 详解(通俗易懂)

        5.DBUtils处理(DML) : 

                这次我们来操作学生表stus(id为自增长主键),如下图所示 : 

JDBC Apache—DBUtils 详解(通俗易懂)

                现要求——
                ①向表中新插入一条“id = 6;name = ‘Carl’;sex = ‘male’;score=499”的记录;
                ②修改name = Five的记录,令其score = 433;
                ③删除id = 5的记录。


                up以ApacheDBUtils_Demo2类为演示类,代码如下 : 

package apache_dbutils; import connection_pool.druid.JDBCUtilsDruid; import org.apache.commons.dbutils.QueryRunner; import java.sql.Connection; import java.sql.SQLException; public class ApacheDBUtils_Demo2 { public static void main(String[] args) throws SQLException { //JDBC核心四部曲 //1.注册驱动(底层会根据druid.properties配置文件中的信息自动注册驱动) //Class.forName("com.mysql.cj.jdbc.Driver"); //2.获取连接 Connection connection = null; connection = JDBCUtilsDruid.getConnection(); //3.执行SQL String sql1 = "INSERT INTO stus " + "VALUES " + "(NULL,?,?,?);"; String sql2 = "UPDATE stus " + "SET score = ? " + "WHERE `name` = ?"; String sql3 = "DELETE FROM stus " + "WHERE id = ?"; QueryRunner queryRunner = new QueryRunner(); int affectedRows1 = queryRunner.update(connection, sql1, "Carl", "male", 499.0); int affectedRows2 = queryRunner.update(connection, sql2, 433.0,"Five"); int affectedRows3 = queryRunner.update(connection, sql3, 5); System.out.println("INSERT语句执行成功了吗?" + (affectedRows1 > 0 ? "Yes!" : "No!")); System.out.println("UPDATE语句执行成功了吗?" + (affectedRows2 > 0 ? "Yes!" : "No!")); System.out.println("DELETE语句执行成功了吗?" + (affectedRows3 > 0 ? "Yes!" : "No!")); //4.释放资源 JDBCUtilsDruid.close(null,null,connection); } } 

                运行结果 : 

JDBC Apache—DBUtils 详解(通俗易懂)

                查询一下stus表,如下 : 

JDBC Apache—DBUtils 详解(通俗易懂)

                修改成功!


四、总结

  • 🆗,以上就是JDBC系列博文第六节的全部内容了。
  • 总结一下,我们从”数据管理”和“结果复用”两个角度分析了传统使用ResultSet的弊端,从而引出了本节要学习的ApacheDBUtils工具类,该工具类可以将结果集中的数据转移到表对应的JavaBean类的实例中,然后将多个实例封装到集合中,便可以达到“复用结果集”的目的。大家需要掌握QueryRunner中query方法和update方法的使用,以及熟悉ResultSetHandler接口的几个常用实现类。
  • 下一节内容——JDBC BasicDAO,我们不见不散。感谢阅读!

        System.out.println(“END—————————————————————————–“); 

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/118099.html

(0)
上一篇 2025-11-15 20:00
下一篇 2025-11-15 20:15

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信