【译】什么时候使用 Spring 6 JdbcClient
原文地址:Spring 6 JdbcClient: When and How to Use it?
一、前言
自 Spring 6.1 起,JdbcClient 为 JDBC 查询和更新操作提供了统一的客户端 API,从而提供了更流畅、更简化的交互模型。本教程演示了如何在各种场景中使用 JdbcClient。
二、Spring 中的数据库访问方法
Spring 框架提供了几种不同的数据库访问方法。两种流行的方法是
- 直接执行 SQL 语句的统一 API,例如 JdbcTemplate
- ORM 框架支持,例如 Hibernate、JPA
统一 API 提供了一种直接高效的方法,允许开发人员以更直接的方式处理 SQL 查询。这种方法的关键组件包括:JdbcTemplate、NamedParameterJdbcTemplate 和 JdbcClient。
对象关系映射(ORM)框架(如 Hibernate)为关系数据库提供了一个抽象层,允许开发人员使用面向对象范例与数据库交互。这使开发人员能够将 Java 对象映射到数据库表,封装并隔离 SQL 查询的细节。
在直接 SQL 执行和 ORM 框架支持之间做出选择取决于多种因素,包括应用程序的复杂性、开发人员的偏好和具体的项目要求。直接 SQL 执行因其简单性和可控性而受到青睐,而 ORM 框架则在优先考虑面向对象设计和抽象的情况下表现出色。
三、JdbcClient 与 JdbcTemplate 的区别
JdbcTemplate 是 Spring Data 中的一个核心类,可简化 JDBC 的使用并消除与传统 JDBC 使用相关的大量模板代码。它提供了执行 SQL 查询、更新和存储过程的方法。
它具有以下功能:
- 执行 SQL 查询、更新和存储过程
- 使用? 占位符传递查询参数
- 通过 RowMapper 或 ResultSetExtractor 进行查询结果行映射
以下面的代码为例
public int getCountOfUsers(String name) {String sql = "SELECT COUNT(*) FROM users WHERE name = ?";return jdbcTemplate.queryForObject(sql, Integer.class, name);
}```JdbcClient 是 Spring 6.1 中引入的增强型统一 JDBC 客户端 API,为命名和位置参数语句提供了流畅的交互模型。它旨在进一步简化 JDBC 操作。它具有以下功能:- 统一支持命名参数和位置参数- 旨在进一步简化 JDBC 操作- 作为不断发展的 Spring 框架的一部分引入以下面的代码为例```java
public int getCountOfUsers(String name) {return jdbcClient.sql("SELECT COUNT(*) FROM users WHERE name = ?").param(name).query(Integer.class).single();
}
在 JdbcTemplate 和 JdbcClient 之间做出选择取决于项目的上下文、Spring 版本和开发人员的偏好。这两种工具都能简化数据库交互,各有各的优势和用例。
四、开始使用 JdbcClient
4.1. Maven
要在 Spring 应用程序中使用 JdbcClient,我们必须确保项目使用的是 Spring 6.1 或 Spring Boot 3.2 的最低版本。
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.2.0-M2</version><relativePath/> <!-- lookup parent from repository -->
</parent><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><!-- other dependencies -->
</dependencies>
4.2. 配置和初始化
要配置 JdbcClient,请确保 Repository 类中包含了 DataSource Bean。
一旦配置完成,JdbcClient 类的实例是线程安全的。一种常用的方法是将 DataSource Bean 依赖注入到 Repository/Dao 类中。JdbcClient 是在存储库构造函数中使用语句 JdbcClient.create() 创建的。Spring 框架会使用构造器注入自动注入 DataSource Bean。
@Repository
public class PersonRepository {private final JdbcClient jdbcClient;public PersonRepository(DataSource dataSource) {this.jdbcClient = JdbcClient.create(dataSource);}//...
}
4.3. 使用 JdbClient 的简单示例
一旦构建了 JdbcClient 实例,我们就可以使用它的便捷方法来执行 SQL 查询。
public Optional<Person> findById(Long id) {String sql = "select id, first_name, last_name, created_at from person where id = :id";return jdbcClient.sql(sql).param("id", id).query((rs, rowNum) -> new Person(rs.getInt("id"), rs.getString("first_name"), rs.getString("last_name"), rs.getTimestamp("created_at").toInstant())).optional();
}
五、为 SQL 语句传递参数
JdbcClient API 在接受 SQL 参数方面非常灵活。让我们来看看几种方法。
5.1. 位置参数
位置参数是查询语句中的占位符,通过其在语句中的位置顺序来识别。这些参数在 SQL 语句中用占位符?
在下面的示例中,查询参数 first_name、last_name 和 created_at 是按分配给方法 StatementSpec.param() 的顺序隐式注册的。
String sql = "insert into person(first_name, last_name, created_at) values (?, ?, ?)";jdbcClient.sql(sql).param("Alex").param("Dave").param(Timestamp.from(Instant.now())).update();
我们还可以使用 StatementSpec.params() 方法将参数作为 var-args 传入,如下所示:
jdbcClient.sql(sql).params("Alex", "Dave", Timestamp.from(Instant.now())).update(keyHolder);
此外,还可以将参数传递为 List。
jdbcClient.sql(sql).params(List.of("Alex", "Dave", Timestamp.from(Instant.now()))).update(keyHolder);
如果我们想进一步确保按正确顺序绑定参数,我们甚至可以传递参数索引,以确保万无一失。
jdbcClient.sql(sql).param(1, "Alex").param(2, "Dave").param(3, Timestamp.from(Instant.now())).update()
5.2. 命名参数
与 NamedParameterJdbcTemplate 类似,JdbcClient 也支持使用占位符 “:paramName” 格式命名 SQL 语句参数。
String sql = "insert into person(first_name, last_name, created_at) values (:firstName, :lastName, :createdAt)";jdbcClient.sql(sql).param("firstName, "Alex").param("lastName", "Dave").param("createdAt", Timestamp.from(Instant.now())).update();
也可以以 Map 的形式传递命名参数,其中键代表命名参数,值在运行时传递给查询。
Map<String, ?> paramMap = Map.of("firstName", "Alex","lastName", "Dave","createdAt", Timestamp.from(Instant.now())
);jdbcClient.sql(sql).params(paramMap).update();
5.3. 对象实例参数(Parameter Source)
为了让事情变得更简单,也可以传递一个字段名与命名参数相匹配的对象(记录类、带有 bean 属性的类或普通字段持有者)。
在下面的示例中,我们使用 Person 对象中的值对数据库执行 INSERT 操作。
Person person = new Person(null, "Clark", "Kent", Instant.now());jdbcClient.sql(sql).paramSource(person).update();
Person 类是一种记录类型,它的字段名与命名参数相匹配。
public record Person(Long id, String firstName, String lastName, Instant createdAt) {
}
同样,我们也可以使用 SimplePropertySqlParameterSource 和 BeanPropertySqlParameterSource 策略。
SqlParameterSource namedParameters = new BeanPropertySqlParameterSource(person);jdbcClient.sql(sql).paramSource(namedParameters).update();
六、将结果集映射到对象
6.1. 使用自定义 RowMapper
从数据库中查询行时,我们可以使用结果集检索列的值,如第 3.3 节所示。但如果我们想增加灵活性和代码的简洁性,可以考虑使用 RowMapper。
下面的 PersonRowMapper 类实现了 RowMapper 接口,并覆盖了 mapRow() 方法,该方法包含将数据库行映射到 Person 实例的逻辑。
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.time.Instant;
import com.howtodoinjava.model.Person;
import org.springframework.jdbc.core.RowMapper;public class PersonRowMapper implements RowMapper<Person> {private PersonRowMapper() {}private static final PersonRowMapper INSTANCE = new PersonRowMapper();public static PersonRowMapper getInstance() {return INSTANCE;}@Overridepublic Person mapRow(ResultSet rs, int rowNum) throws SQLException {return new Person(rs.getLong("id"),rs.getString("first_name"),rs.getString("last_name"),getInstantFromTimestamp(rs.getTimestamp("created_at")));}private Instant getInstantFromTimestamp(Timestamp timestamp) {return (timestamp != null) ? timestamp.toInstant() : null;}
}
现在,我们可以在 query() 方法中使用 PersonRowMapper,Spring 会在内部使用映射器,并直接获取 Person 实例。
String querySql = "select id, first_name, last_name, created_at from person where id = :id";Optional<Person> personOptional = jdbcClient.sql(querySql).param("id", 1).query(PersonRowMapper.getInstance()).optional();
6.2. 使用类 Mapping
如果因为在类字段和数据库列之间有一个直接的字段映射,而创建 PersonRowMapper 显得很费力,那么可以直接传递 query() 方法的类类型,这样也可以。
String querySql = "select id, first_name, last_name, created_at from person where id = :id";Optional<Person> personOptional = jdbcClient.sql(querySql).param("id", 1).query(Person.class).optional();
译者注:再看一下 Person 的记录类是如何定义的,看起来会自动完成下划线分隔命名和驼峰命名的转换。
public record Person(Long id, String firstName, String lastName, Instant createdAt) {
}
七、SQL 查询和更新操作
JdbcClient 支持所有类型的数据库操作,如选择、创建、更新和删除记录。
- query() 方法执行给定的 SQL查询,返回的查询结果提供了多个封装方法,如映射类(Class Mapping)、行映射器(RowMapper)、行回调处理程序(RowCallbackHandler)和结果集提取器(ResultSetExtractor)
- update() 方法将提供的 SQL 语句作为更新执行。它总是返回一个受影响行数的 int 值。
这些方法的示例在前面的章节中已经介绍过,不再赘述。
八、批量插入和存储过程的考虑因素
JdbcClient 是一个灵活但非常简化的界面,仅用于 JDBC 查询/更新语句。如果您需要做更复杂的事情,如执行批处理操作或调用存储过程,JdbcClient 可能无法提供您需要的所有功能。
在这种情况下,您可能需要使用 Spring 提供的其他工具,如 SimpleJdbcInsert 或 SimpleJdbcCall。
另外,您也可以直接使用更基本的 JdbcTemplate 来完成 JdbcClient 无法完全覆盖的任务。这就好比在工具箱中装有不同的工具,您可以根据工作需要选择最合适的工具。
九、结论
在本教程中,我们探讨了使用 Spring 6 JdbcClient 进行查询和更新操作的初始配置和基础知识。如前所述,JdbcClient 为 JDBC 交互提供了简化和统一的 API,使代码更加简洁易读。
学习愉快
Github 上的源码地址
相关文章:
【译】什么时候使用 Spring 6 JdbcClient
原文地址:Spring 6 JdbcClient: When and How to Use it? 一、前言 自 Spring 6.1 起,JdbcClient 为 JDBC 查询和更新操作提供了统一的客户端 API,从而提供了更流畅、更简化的交互模型。本教程演示了如何在各种场景中使用 JdbcClient。 二…...
VR全景:赋能城市园区建设,打造3DVR城市名片
近年来,很多城市都在大力发展数字化经济建设,以VR全景技术赋能现代化城市和园区建设,为城市园区展示带来了全新的可能性。借助3D、VR技术把现实城市和园区搬到互联网上进行全方位展示,将城市园区的形象、景观、规划布局等1&#x…...
孟德尔随机化写作技巧mr
...
社会媒体营销提问常用的ChatGPT通用提示词模板
如何制定有效的社会媒体营销策略? 如何选择适合的社会媒体平台进行营销? 如何创造有吸引力的社会媒体内容,提高用户参与度和分享率? 如何运用社交媒体广告来增加品牌曝光和用户转化? 如何建立和维护社交媒体账号和…...
智慧储能边缘计算网关应用,提升能源效率
智慧储能通过边缘计算网关物联网技术来实现对储能电池等设备的在线监控和远程管理。边缘计算网关可以将储能数据转化为可用的信息,并传输到储能系统中,为储能管理提供优化与调度等数据支持。 边缘计算网关在智慧储能系统中起到了关键的作用。IR4000边缘计…...
利用 Apache Ranger 管理 Amazon EMR 中的数据权限
需求背景简介 系统安全通常包括两个核心主题:身份验证和授权。一个解决“用户是谁”的问题,另一个解决“用户允许执行什么操作”的问题。在大数据领域,Apache Ranger 是最受欢迎的授权选择之一,它支持所有主流大数据组件ÿ…...
HarmonyOS(三)—— 应用程序入口—UIAbility
前言 学习过android的同学都是知道Activity,Activity是Android组件中最基本也是最为常见用的四大组件之一,用户可以用来交互为了完成某项任务。 Activity中所有操作都与用户密切相关,是一个负责与用户交互的组件,可以通过setCon…...
Vuetify:定制化、响应式的 Vue UI 库 | 开源日报 No.83
vuetifyjs/vuetify Stars: 38.1k License: MIT Vuetify 是一个无需设计技能的 UI 库,具有精美手工制作的 Vue 组件。它具有以下核心优势和主要功能: 可定制性:使用 SASS/SCSS 进行广泛自定义,并提供默认配置和蓝图。响应式布局&…...
使用PySpark 结合Apache SystemDS 进行信号处理分析 (离散傅立叶变换)的简单例子
文章大纲 简介 :什么是 SystemDS ?环境搭建与数据 准备数据预处理模型训练 与 结果评估参考文献简介 :什么是 SystemDS ? SystemDS is an open source ML system for the end-to-end data science lifecycle from data integration, cleaning, and feature engineering, ov…...
AT89S52单片机的最小应用系统
目录 一.时钟电路设计 1.内部时钟方式 2.外部时钟方式 3.时钟信号的输出 二.机器周期,指令周期与指令时序 1.时钟周期 2.机器周期 3.指令周期 三.复位操作和复位电路 1.复位操作 2 复位电路设计 四.低功耗节电模式 AT89S52本身片内有8KB闪烁存储器&am…...
Pytorch中的tensor维度理解
Pytorch中的tensor维度理解 文章目录 Pytorch中的tensor维度理解摘要打消心理恐惧,从三维学起三维tensor参考文献 摘要 面对pytorch编程中的tensor时,我不时会感到恐惧。对里面数据是怎么排布的,一直没有一个直观的理解。今天我想把这个事情…...
2019年12月 Scratch(三级)真题解析#中国电子学会#全国青少年软件编程等级考试
Scratch等级考试(1~4级)全部真题・点这里 一、单选题(共25题,每题2分,共50分) 第1题 怎样修改图章的颜色? A:只需要一个数字来设置颜色 B:设置RGB的值 C:在画笔中设置颜色、饱和度、亮度 D:在外观中设置或修改角色颜色特效 答案:D 在外观中设置或修改角色颜色特…...
matlab-实现-BP-神经网络
最近写论文用到了很多神经网络和优化算法,算是废了不少精力收集起来的,还是整理出来分享给大家,以免浪费了。 本篇以最简单的 BP神经网络开始吧 详细的实现步骤如下: 1.环境准备:清空环境变量、关闭开启的图窗、清空变…...
基于go-zero的rpc服务示例
以下是一个基于 go-zero 框架的简单 RPC 服务示例,该示例包括一个服务端和一个客户端通过 gRPC 进行通信。 服务端 1、定义 .proto 文件 在 rpc/add 目录下创建 adder.proto 文件,定义 RPC 服务: syntax "proto3";package add…...
【算法】奇偶游戏(带权并查集)
题目 小 A 和小 B 在玩一个游戏。 首先,小 A 写了一个由 0 和 1 组成的序列 S,长度为 N。 然后,小 B 向小 A 提出了 M 个问题。 在每个问题中,小 B 指定两个数 l 和 r,小 A 回答 S[l∼r] 中有奇数个 1 还是偶数个 …...
补充:linux rsyslog配置多端口监听(基于UDP)
rsyslog默认udp监听端口为514,我们可以配置rsyslog基于udp的多端口监听,实现监控的丰富性 1.环境信息 环境信息 HostnameIpAddressOS versionModuleNotersyslog1192.168.10.246Red Hat Enterprise Linux Server release 7.7 (Maipo)rsyslogd 8.24.0-38.el7linux基础配置 Li…...
详解StringBuilder和StringBuffer(区别,使用方法,含源码讲解)
目录 一.为什么要使用StringBuilder和StringBuffer 字符串的不可变性 性能损耗 二.StringBuilder和StringBuffer StringBuffer源码讲解 使用方式 三.常用方法总结 示例: 四.StringBuilder和StringBuffer的区别 一.为什么要使用StringBuilder和StringBuffe…...
九、sdl显示bmp图片
前言 SDL中内置加载BMP的API,使用起来会更加简单,便于初学者学习使用SDL 如果需要加载JPG、PNG等其他格式的图片,可以使用第三方库:SDL_image 测试环境: ffmpeg的4.3.2自行编译版本windows环境qt5.12sdl2.0.22&…...
ROS设置DHCP option121
配置时,了解格式很关键,16进制填写格式如下: 将要访问的IPV4地址:192.168.100.0/24 192.168.30.254 转换为:掩码 目标网段 网关 0x18c0a864c0a81efe,0不用填写 ROS配置如下图: 抓…...
④【Set】Redis常用数据类型: Set [使用手册]
个人简介:Java领域新星创作者;阿里云技术博主、星级博主、专家博主;正在Java学习的路上摸爬滚打,记录学习的过程~ 个人主页:.29.的博客 学习社区:进去逛一逛~ Redis Set ④Redis Set 操作命令汇总1. sadd …...
AI人工智能——解读智能算力服务质量模型
本文介绍了智能算力服务质量模型ICPS-QM的核心内容。随着大模型参数量呈指数性增长和智能算力服务需求的激增,国家高度重视算力网络一体化,并发布了相关实施意见。然而,算力网络存在云和网相对独立、跨云一体化资源调度困难等问题,智算服务也面临算力不足、能耗高、服务安全…...
会炒股的程序员10,个人投资体系
你这段话的核心可以压缩成一句: 股市不是单纯交易公司,而是在交易“公司现实、群体预期、个人心理和时间约束”的叠加结果。 所以投资最难的地方,不是知道一句正确的话,而是同时承受几种互相矛盾的真相。 一、市场为什么难 好公司…...
AI和大模型——harness编程
一、Vibe编程 谈harness编程就要从Vibe编程说起。所谓Vibe编程,中文一般称为氛围编程或沉浸式编程,它指是由AI驱动的一种软件开发的新范式。都上升到范式的级别了,肯定看起来了更高大上了。其实不然,说白了就是开发者指挥着AI来编…...
PEI转染优化全流程指南(二):AAV包装与慢病毒生产关键参数深度解析(含实操策略)
摘要: 细胞转染技术是基因治疗与细胞治疗开发中的核心环节。PEI转染作为主流非病毒递送方式,其效率受质粒比例、DNA与PEI比率、孵育条件、细胞状态及病毒收获时间等多因素影响。本文系统梳理PEI转染及AAV/慢病毒包装过程中的关键优化参数,为提…...
程序员离婚流程指南:你的代码、期权、知识产权和加班,都写在民法典婚姻法律里
你可能不知道,你每天敲的代码、手里的期权、甚至深夜加班的时间和强度,都可能成为离婚时财产分割和抚养权争夺中的关键因素。对于技术从业者来说,婚姻财产问题远比普通人想象的复杂。我一个帮助过多位程序员处理婚姻纠纷的律师,今…...
精准制胜:GPT-Image-2的实用之道
从用户视角看 GPT-Image-2:真正好用的不是“华丽”,而是“精准”2026 年,AI 图像生成工具已经不算新鲜,但“好不好用”这件事,依然没有标准答案。很多人第一次接触图像生成时,都会被炫酷效果吸引࿱…...
B/S与C/S:浏览器VS客户端,谁才是数字孪生的主角
B/S架构:“政治正确”下的无奈妥协B/S(浏览器/服务器)架构曾几乎成为数字孪生项目选型的“政治正确”——无需安装、扫码即用、跨平台分享,这些光环使它成为项目招标书中最为亮眼的一行。当数字孪生从一个个“增量”地标项目转向盘…...
运维入门指南:从基础到实战
运维基础概念运维(Operations)的核心目标是保障系统稳定、高效运行,涵盖服务器管理、网络监控、故障排查等。常见运维方向包括:系统运维:Linux/Windows服务器维护、用户权限管理。网络运维:路由器、交换机配…...
TypeScript + CocosCreator:封装一个可复用的微信用户信息管理模块(WechatManager.ts)
TypeScript CocosCreator:构建高可用微信用户信息管理模块 在当今移动游戏开发领域,微信小游戏因其庞大的用户基础和便捷的社交分享能力,已成为开发者不可忽视的平台。然而,微信API的复杂性和平台特殊性常常让开发者陷入重复造轮…...
React-Cropper深度解析:从基础配置到高级用法
React-Cropper深度解析:从基础配置到高级用法 【免费下载链接】react-cropper Cropperjs as React component 项目地址: https://gitcode.com/gh_mirrors/re/react-cropper React-Cropper是一个基于Cropper.js的强大React图片裁剪组件,它让开发者…...
