apache DbUtils 组件核心原理与应用

Apache DbUtils 是一个 Apache 组织提供的开源 JDBC 工具类库,它对 JDBC 进行了简单封装,使得数据库操作更加简洁和安全。DbUtils 的核心组件主要包括 QueryRunner、ResultSetHandler 和 RowProcessor,下面将对这些组件进行介绍,并结合源代码分析其工作原理。

核心组件介绍与原理

  1. QueryRunner:
  • QueryRunner 是执行数据库查询、更新和插入操作的入口类。
  • 它提供同步和异步服务,并且可以自动创建和管理 JDBC 资源(如 Connection、Statement、ResultSet)。
  • QueryRunner 还支持批处理操作,可以一次性执行多个 SQL 语句。
  1. ResultSetHandler:
  • ResultSetHandler 接口负责将 JDBC 的 ResultSet 转换成其他格式的数据。
  • DbUtils 提供了多种 ResultSetHandler 的实现,用于- 将结果集转换为数组、列表、Map、JavaBean 等格式。
  1. RowProcessor:
  • RowProcessor 用于处理行记录,将 ResultSet 的当前行转换为 Java 对象。
  • BasicRowProcessor 是 DbUtils 中的一个默认实现,用于将 SQL 行转换为 Map 或 JavaBean。

逻辑步骤:

  1. 创建 QueryRunner 实例:
  • 可以通过传递 DataSource 或 Connection 来创建 QueryRunner 对象。
  1. 编写 SQL 语句:
  • 准备要执行的 SQL 查询或更新语句。
  1. 选择 ResultSetHandler:
  • 根据需要处理的数据格式选择合适的 ResultSetHandler 实现。
  1. 执行查询或更新:
  • 使用 QueryRunner 的 query 或 update 方法执行 SQL 语句,并传入 ResultSetHandler。
  1. 处理结果:
  • ResultSetHandler 将 ResultSet 转换为相应的数据格式,并返回。
  1. 资源关闭:
  • DbUtils 提供了方法来安全关闭 JDBC 资源,避免资源泄漏。

源代码分析:

以 QueryRunner 和 BeanHandler 为例,分析其源码:

QueryRunner queryRunner = new QueryRunner();
BeanHandler<Emp> handler = new BeanHandler<>(Emp.class);
Emp emp = queryRunner.query("SELECT * FROM emp WHERE id = ?", handler, id);
  1. 创建 QueryRunner 对象:实例化 QueryRunner,准备执行数据库操作。

  2. 创建 BeanHandler 对象:BeanHandler 是 ResultSetHandler 的一个实现,用于将 ResultSet 的每一行转换为一个 JavaBean 对象。

  3. 执行查询:QueryRunner 的 query 方法接受 SQL 语句、ResultSetHandler 和参数,执行查询并返回结果。

QueryRunner 是 Apache DbUtils 中的一个核心类,它封装了 JDBC 的大部分操作,使得执行 SQL 语句更加方便和安全。以下是 QueryRunner 类的详细介绍和源码实现逻辑的分析:

QueryRunner 类介绍:

QueryRunner 类提供了执行各种 SQL 语句的方法,包括:

  • update:用于执行更新操作(如 INSERT、UPDATE、DELETE)。
  • query:用于执行查询操作并返回单个结果。
  • execute:用于执行 DDL 语句或存储过程调用。

它还支持批处理操作,可以一次性执行多个 SQL 语句。

源码实现逻辑:

QueryRunner 的实现涉及到几个关键的步骤:

  1. 获取 JDBC 连接:QueryRunner 的方法通常接收一个 Connection 对象作为参数。在执行 SQL 之前,你需要从数据源或连接池中获取一个 Connection。

  2. 准备 SQL 语句:QueryRunner 使用 PreparedStatement 来准备 SQL 语句。这有助于防止 SQL 注入攻击。

  3. 填充参数:如果 SQL 语句包含占位符(如 ?),QueryRunner 会根据提供的参数数组填充这些占位符。

  4. 执行 SQL:根据执行的 SQL 类型(更新或查询),QueryRunner 会调用适当的方法来执行 SQL。

  5. 处理结果:对于查询操作,QueryRunner 使用 ResultSetHandler 来处理 ResultSet 并将其转换为期望的结果类型。

  6. 资源管理:QueryRunner 提供了方法来确保所有 JDBC 资源(如 PreparedStatement 和 ResultSet)在使用后都被正确关闭,即使在发生异常的情况下也是如此。

源码分析:

以下是 QueryRunner 中 query 方法的一个简化示例,展示了其基本的实现逻辑:

public <T> T query(String sql, ResultSetHandler<T> rsh, Object... params) throws SQLException {
    Connection conn = null;
    PreparedStatement pstmt = null;
    ResultSet rs = null;
    try {
        conn = getConnection(); // 获取 JDBC 连接
        pstmt = conn.prepareStatement(sql);
        this.fillStatement(pstmt, params); // 填充参数
        rs = pstmt.executeQuery(); // 执行查询
        return rsh.handle(rs); // 使用 ResultSetHandler 处理结果集
    } finally {
        // 关闭资源,即使在发生异常的情况下
        JdbcUtils.close(rs);
        JdbcUtils.close(pstmt);
        JdbcUtils.close(conn);
    }
}

在这个简化的示例中,query 方法接收 SQL 语句、一个 ResultSetHandler 实例和一些参数。它使用 PreparedStatement 来执行 SQL 语句,并使用提供的 ResultSetHandler 来处理查询结果。

详细解释:

  • getConnection():这是一个从数据源或连接池中获取 Connection 的方法。在实际的 QueryRunner 实现中,这可以是传递给 QueryRunner 构造函数的 DataSource 或在方法中直接传递的 Connection。

  • fillStatement(pstmt, params):这是一个辅助方法,用于将参数绑定到 PreparedStatement 的占位符上。

  • rsh.handle(rs):这是 ResultSetHandler 接口的核心方法,它定义了如何处理 ResultSet。不同的 ResultSetHandler 实现会将 ResultSet 转换为不同的类型,如 JavaBean、Map、List 等。

  • finally 块:确保所有 JDBC 资源在使用后都被正确关闭。这是通过 JdbcUtils.close() 方法实现的,它是一个安全关闭资源的工具方法,可以处理 null 值和潜在的 SQLException。

QueryRunner 的设计哲学是简化 JDBC 编程,同时提供足够的灵活性来处理各种数据库操作。通过封装 JDBC 的复杂性,QueryRunner 使得开发者可以更专注于业务逻辑而不是底层的数据库操作细节。

应用操作

以下是一些 DbUtils 组件的应用案例,展示了如何使用 DbUtils 执行常见的数据库操作:

  1. 基本的数据库查询

使用 QueryRunner 和 BeanHandler 来执行查询并将结果映射到 JavaBean 对象。

QueryRunner queryRunner = new QueryRunner();
BeanHandler<User> handler = new BeanHandler<>(User.class);
User user = queryRunner.query(conn, "SELECT * FROM users WHERE id = ?", handler, 1);
  1. 查询并返回多条记录

使用 BeanListHandler 来处理多条记录,并将结果集映射为 JavaBean 对象的列表。

List<User> users = queryRunner.query(conn, "SELECT * FROM users", new BeanListHandler<>(User.class));
  1. 执行更新操作

使用 QueryRunner 的 update 方法来执行 INSERT、UPDATE 或 DELETE 语句。

int rowsInserted = queryRunner.update(conn, "INSERT INTO users(name, email) VALUES(?, ?)", "John Doe", "john@example.com");
  1. 批量更新

QueryRunner 支持批处理,可以一次性执行多个 SQL 更新操作。

Object[][] batchArgs = {
    {"John", "john@example.com"},
    {"Jane", "jane@example.com"}
};
queryRunner.batch(conn, "INSERT INTO users(name, email) VALUES(?, ?)", batchArgs);
  1. 处理聚集函数

使用 ScalarHandler 来处理返回单行单列的查询,如计数或总和。

Long count = queryRunner.query(conn, "SELECT COUNT(*) FROM users", new ScalarHandler<Long>(Long.class));
  1. 使用连接池

DbUtils 可以与连接池(如 DBCP 或 HikariCP)一起使用,以提高性能。

DataSource dataSource = ...; // 初始化数据源
QueryRunner queryRunner = new QueryRunner(dataSource);
// 使用 queryRunner 执行操作,不需要手动关闭连接
  1. 事务处理

DbUtils 提供了一些基本的事务管理方法,但通常与 Spring 或其他框架的事务管理集成更常见。

Connection conn = ...; // 获取数据库连接
try {
    conn.setAutoCommit(false); // 开始事务
    // 执行一系列数据库操作
    conn.commit(); // 提交事务
} catch (SQLException e) {
    conn.rollback(); // 回滚事务
    throw e;
} finally {
    conn.setAutoCommit(true); // 确保设置自动提交
    DbUtils.closeQuietly(conn); // 关闭连接
}
  1. 自定义 ResultSetHandler

如果预定义的 ResultSetHandler 实现不符合需求,可以自定义实现。

public class CustomHandler implements ResultSetHandler<List<MyBean>> {
    public List<MyBean> handle(ResultSet rs) throws SQLException {
        List<MyBean> list = new ArrayList<>();
        while (rs.next()) {
            // 根据需要从 ResultSet 中提取数据并创建 MyBean 对象
            MyBean bean = new MyBean();
            // ...
            list.add(bean);
        }
        return list;
    }
}

然后使用自定义的 ResultSetHandler:

List<MyBean> beans = queryRunner.query(conn, "SELECT * FROM my_table", new CustomHandler());

这些案例展示了 DbUtils 在实际应用中的灵活性和强大功能。通过这些组件,DbUtils 使得 JDBC 编程变得更加简洁和易于管理。

最后

DbUtils 的设计思想是简化 JDBC 编程,通过封装 JDBC 操作,减少样板代码,提高开发效率。它通过 QueryRunner、ResultSetHandler 和 RowProcessor 的协同工作,实现了对 JDBC 资源的精细化管理,同时避免了资源泄漏的风险。DbUtils 的使用不涉及复杂的配置和ORM映射,适合需要快速、轻量级数据库操作的场景。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/585773.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

使用Gradio搭建聊天UI实现质谱AI智能问答

一、调用智谱 AI API 1、获取api_key 智谱AI开放平台网址&#xff1a; https://open.bigmodel.cn/overview 2、安装库pip install zhipuai 3、执行一下代码&#xff0c;调用质谱api进行问答 from zhipuai import ZhipuAIclient ZhipuAI(api_key"xxxxx") # 填写…

回溯Backtracking Algorithm

目录 1) 入门例子 2) 全排列-Leetcode 46 3) 全排列II-Leetcode 47 4) 组合-Leetcode 77 5) 组合总和-Leetcode 39 6) 组合总和 II-Leetcode 40 7) 组合总和 III-Leetcode 216 8) N 皇后 Leetcode 51 9) 解数独-Leetcode37 10) 黄金矿工-Leetcode1219 其它题目 1) 入…

汽车热辐射、热传导、热对流模拟加速老化太阳光模拟器系统

汽车整车结构复杂&#xff0c;材料种类繁多&#xff0c;在使用过程中会面临各种严酷气候环境的考验&#xff0c;不可避免会出现零部件材料老化、腐蚀等不良现象&#xff0c;从而影响汽车的外观、功能&#xff0c;甚至产生安全隐患。因此&#xff0c;分析汽车零部件材料老化腐蚀…

【图论】图论基础

图论不同地方讲的不太一样&#xff0c;本文仅限作者的理解 定义 图是一般由点集 V V V 和边集 E E E 组成。 对于 v ∈ V v\in V v∈V&#xff0c;称 v v v 为该图的一个节点。 对于 e ∈ E e\in E e∈E&#xff0c;一般用二元组 ( u , v ) (u,v) (u,v) 表示 e e e&am…

Matlab生成txt文件导入到Vivado仿真

Matlab处理数据并将其写入txt文件 %% Txt Generate pre_RS_datadec2bin(simDataIn,8); %将数据转化为8bit的二进制 fidfopen("F:\FPGA\Xilinx_vivado\project\dvbstestbench\dbvs\matlab\pre_RS_data.txt","wt"); for i1:n*nMessages %数据…

记一次使用Notepad++正则表达式批量替换SQL语句

目录 一、需求二、解决方案三、正则解析 一、需求 存在如下SQL建表脚本&#xff1a; CREATE TABLE "BUSINESS_GOODS" ( "ID" VARCHAR(32) NOT NULL, "GOODS_CODE" VARCHAR(50), "GOODS_NAME" VARCHAR(100), ... NOT CLUSTER PRIMARY…

设计模式第一次测验 | 数据库连接设计(单例模式、抽象工厂模式、工厂模式)

需求如下&#xff1a; 我们需要设计一个工具&#xff0c;它负责创建一个与数据库软件的连接池。 该工具由在容器&#xff08;Tomcat等&#xff09;内运行的应用程序用来连接数据库软件。 在同一个容器中运行的所有应用程序共享同一个连接池对象。 现在我们需要支持以下数据库软…

TCP/IP和HTTP协议

TCP/IP OSI 七层模型在提出时的出发点是基于标准化的考虑&#xff0c;而没有考虑到具体的市场需求&#xff0c;使得该模型结构复杂&#xff0c;部分功能冗余&#xff0c;因而完全实现 OSI 参考模型的系统不多。而 TCP/IP 参考模型直接面向市场需求&#xff0c;实现起来也比较…

arthas如何排除CPU使用率过高问题

1、首先启动arthas java -jar arthas-boot.jar 2、使用thread查看各线程CPU使用率 thread 可以看到CPU使用率最高的有2个线程&#xff0c;以线程ID为19的为例子&#xff1a; 输入thread 19查看线程19的堆栈信息&#xff1a; thread 19 可以看到是(CpuController.java:78行…

「C/C++ 01」类型转换与整型提升

目录 一、类型转换和截断问题 1. 隐式类型转换 2. 强制类型转换 3. 截断问题 二、整型提升 0. 算数表达式的计算过程 1. 整型提升是什么&#xff1f; 2. 为什么要整型提升&#xff1f; 3. 如何进行整型提升 4. 唯一的注意事项 5. 通过在vs中的监视窗口来观察整型提升 6. 整型…

螺旋角和导程、转位后的齿轮有什么关系?

最近和小伙伴聊到了一个问题&#xff1a;斜齿轮螺旋角和导程的关系&#xff0c;主要是在遇到在采用转位设计方式的刀具时&#xff0c;更觉得有点迷惑&#xff0c;今天咱们就聊聊这个事儿。 先来说斜齿轮螺旋角和导程的关系&#xff1a; 斜齿轮是有多个螺旋面组成的&#xff0…

力扣153. 寻找旋转排序数组中的最小值

Problem: 153. 寻找旋转排序数组中的最小值 文章目录 题目描述思路复杂度Code 题目描述 思路 1.初始化左右指针left和right&#xff0c;指向数组的头和尾&#xff1b; 2.开始二分查找&#xff1a; 2.1.定义退出条件&#xff1a;当left right时退出循环&#xff1b; 2.2.当nums…

【会员单位】浙江晧月水务科技有限公司

中华环保联合会理事单位 水环境治理专业委员会副主任委员单位 公司成立于2018年3月14日&#xff0c;是专业研究废水处理业务的国家高新技术企业。 公司自主研发的脱硫废水“零排放”的技术&#xff0c;不仅适应性好&#xff0c;技术先进&#xff0c;智慧化程度高&#xff0c…

深度学习中的变形金刚——transformer

很荣幸能和这些大牛共处一个时代。网络结构名字可以是一个卡通形象——变形金刚&#xff0c;论文名字可以来源于一首歌——披头士乐队的歌曲《All You Need Is Love》。 transformer在NeurIPS2017诞生&#xff0c;用于英语-德语&#xff0c;英语-法语的翻译&#xff0c;在BLEU…

21 如何进行高保真压测和服务扩容?

在后台架构中&#xff0c;压测非常常见&#xff0c;也是必须的工作。它能够帮我们发现微服务架构中的性能瓶颈&#xff0c;以及知道构建的微服务能承载的流量极限值。 但实际情况是&#xff0c;很多压测并不能发现瓶颈点和微服务所能承载的真实流量极限值。一方面是因为压测时…

LiveGBS user/save 逻辑缺陷漏洞复现(CNVD-2023-72138)

0x01 产品简介 LiveGBS是安徽青柿信息科技有限公司研发的一款国标(GB28181)流媒体服务软件,可提供提供用户管理及Web可视化页面管理,开源的前端页面源码;提供设备状态管理,可实时查看设备是否掉线等信息等。 0x02 漏洞概述 LiveGBS user/save 接口处存在逻辑缺陷漏洞,未…

【Qt之OpenGL】01创建OpenGL窗口

1.创建子类继承QOpenGLWidget 2.重写三个虚函数 /** 设置OpenGL的资源和状态,最先调用且调用一次* brief initializeGL*/ virtual void initializeGL() override; /** 设置OpenGL视口、投影等&#xff0c;当widget调整大小(或首次显示)时调用* brief resizeGL* param w* para…

请求接口报错:java.lang.IllegalStateException: argument type mismatch

目录 一、场景二、报错信息三、控制器四、接口调用五、原因六、解决 一、场景 1、调用后端接口报错 2、接口参数以Json方式传递 – 二、报错信息 java.lang.IllegalStateException: argument type mismatch Controller [com.xxx.huarunshouzheng.controller.MallControlle…

Ubuntu如何更换 PyTorch 版本

环境&#xff1a; Ubuntu22.04 WLS2 问题描述&#xff1a; Ubuntu如何更换 PyTorch 版本考虑安装一个为 CUDA 11.5 编译的 PyTorch 版本。如何安装旧版本 解决方案&#xff1a; 决定不升级CUDA版本&#xff0c;而是使用一个与CUDA 11.5兼容的PyTorch版本&#xff0c;您可…

75、堆-前K个高频元素

思路 这道题还是使用优先队列&#xff0c;是要大根堆&#xff0c;然后创建一个类&#xff0c;成员变量值和次数。大根堆基于次数排序。前k个就拿出前k的类的值即可。代码如下&#xff1a; class Solution {public int[] topKFrequent(int[] nums, int k) {if (nums null || …
最新文章