SpringBoot3.2新特性之JdbcClient的使用

 更新时间:2025年08月25日 10:57:15   作者:秃了也弱了。  
本文主要介绍了SpringBoot3.2新特性之JdbcClient的使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

一、简介

Spring 6.1 中新添加了 JdbcClient 接口,它提供了 Fluent 风格的 API,统一了 JdbcTemplate 和 NamedParameterJdbcTemplate 的 Facade,支持链式操作。

有了 JdbcClient 后就可以使用 Fluent 风格的 API 定义查询、设置参数以及执行数据库操作了。

该功能简化了 JDBC 操作,使其更易读、更易懂。然而,对于 JDBC 批处理操作和存储过程的调用,仍然需要使用 JdbcTemplate 和 NamedParameterJdbcTemplate 类。

SpringBoot3.2中也集成了JdbcClient ,配置也很简单,只要引入相关包,Spring Boot 框架会自动发现 application.properties 中的 DB 连接属性,并在应用启动时创建 JdbcClient Bean。之后,JdbcClient Bean 可以在任何类中注入、使用。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jdbc</artifactId>
</dependency>
@Component
public class DbService {
	// 直接使用即可
    @Autowired
    private JdbcClient jdbcClient;
}

二、使用

1、支持隐式位置参数

使用占位符 ? 来通过位置绑定 SQL 参数。

List<Student> getStudentsOfGradeStateAndGenderWithPositionalParams(int grade, String state, String gender) {
    String sql = "select student_id, student_name, age, grade, gender, state from student"
            + " where grade = ? and state = ? and gender = ?";
    return jdbcClient.sql(sql)
      .param(grade)
      .param(state)
      .param(gender)
      .query(new StudentRowMapper()).list();
}

@Test
void givenJdbcClient_whenQueryWithPositionalParams_thenSuccess() {
    List<Student> students = studentDao.getStudentsOfGradeStateAndGenderWithPositionalParams(1, "New York", "Male");
    assertEquals(6, students.size());
}

在上述方法中,参数 grade、state 和 gender 是按照方法 param() 的调用顺序隐式注册的。最后,当调用 query() 方法时,语句将被执行,并通过 RowMapper 转换、获取结果,和 JdbcTemplate 一样。

query() 方法还支持 ResultSetExtractor 和 RowCallbackHandler 参数。

在调用 list() 方法之前,不会检索到任何结果。此外,还支持其他获取结果的操作,如 optional()、set()、single() 和 stream()。

还可以通过 params 方法使用可变参数来设置 SQL 参数:

Student getStudentsOfGradeStateAndGenderWithParamsInVarargs(int grade, String state, String gender) {
    String sql = "select student_id, student_name, age, grade, gender, state from student"
      + " where grade = ? and state = ? and gender = ? limit 1";
    return jdbcClient.sql(sql)
      .params(grade, state, gender)
      .query(new StudentRowMapper()).single();
}

@Test
void givenJdbcClient_whenQueryWithParamsInVarargs_thenSuccess() {
    Student student = studentDao.getStudentsOfGradeStateAndGenderWithParamsInVarargs(1, "New York", "Male");
    assertNotNull(student);
}

如上所示,使用 params() 方法替换了 param() 方法,后者使用可变参数。最后通过 single() 方法来检索一条记录。

params() 方法还有一个重载版本,可以接收一个参数 List。

Optional<Student> getStudentsOfGradeStateAndGenderWithParamsInList(List params) {
    String sql = "select student_id, student_name, age, grade, gender, state from student"
      + " where grade = ? and state = ? and gender = ? limit 1";
    return jdbcClient.sql(sql)
      .params(params)
      .query(new StudentRowMapper()).optional();
}

@Test
void givenJdbcClient_whenQueryWithParamsInList_thenSuccess() {
    List params = List.of(1, "New York", "Male");
    Optional<Student> optional = studentDao.getStudentsOfGradeStateAndGenderWithParamsInList(params);
    if(optional.isPresent()) {
        assertNotNull(optional.get());            
    } else {
        assertThrows(NoSuchElementException.class, () -> optional.get());
    }
}

除了 params(List<?> values),这里还通过 optional() 方法返回了 Optional<Student> 对象。

2、通过索引设置位置参数

如果需要设置 SQL 语句参数的位置,可以使用 param(int jdbcIndex, Object value) 方法:

List<Student> getStudentsOfGradeStateAndGenderWithParamIndex(int grade, String state, String gender) {
    String sql = "select student_id, student_name, age, grade, gender, state from student"
      + " where grade = ? and state = ? and gender = ?";
    return jdbcClient.sql(sql)
      .param(1, grade)
      .param(2, state)
      .param(3, gender)
      .query(new StudentResultExtractor());
}

@Test
void givenJdbcClient_whenQueryWithParamsIndex_thenSuccess() {
    List<Student> students = studentDao.getStudentsOfGradeStateAndGenderWithParamIndex(
      1, "New York", "Male");
    assertEquals(6, students.size());
}

在该方法中,明确指定了参数的位置。此外,还使用了 query(ResultSetExtractor rse) 方法。

3、支持 Name / Value 对命名参数

JdbcClient 还支持使用占位符 : 绑定命名的 SQL 语句参数,这是 NamedParameterJdbcTemplate 的特性。

param() 方法也可以设置键值对类型的参数:

int getCountOfStudentsOfGradeStateAndGenderWithNamedParam(int grade, String state, String gender) {
    String sql = "select student_id, student_name, age, grade, gender, state from student"
      + " where grade = :grade and state = :state and gender = :gender";
    RowCountCallbackHandler countCallbackHandler = new RowCountCallbackHandler();
    jdbcClient.sql(sql)
      .param("grade", grade)
      .param("state", state)
      .param("gender", gender)
      .query(countCallbackHandler);
    return countCallbackHandler.getRowCount();
}

@Test
void givenJdbcClient_whenQueryWithNamedParam_thenSuccess() {
    Integer count = studentDao.getCountOfStudentsOfGradeStateAndGenderWithNamedParam(1, "New York", "Male");
    assertEquals(6, count);
}

在上述方法中,使用了命名参数。此外,还使用了 query(RowCallbackHandler rch) 方法来获取结果。

4、通过 Map 设置命名参数

也可以通过 params(Map<String,?> paramMap) 方法,使用 Map 对象来设置命名参数:

List<Student> getStudentsOfGradeStateAndGenderWithParamMap(Map<String, ?> paramMap) {
    String sql = "select student_id, student_name, age, grade, gender, state from student"
      + " where grade = :grade and state = :state and gender = :gender";
    return jdbcClient.sql(sql)
      .params(paramMap)
      .query(new StudentRowMapper()).list();
}

@Test
void givenJdbcClient_whenQueryWithParamMap_thenSuccess() {
    Map<String, ?> paramMap = Map.of(
      "grade", 1,
      "gender", "Male",
      "state", "New York"
    );
    List<Student> students = studentDao.getStudentsOfGradeStateAndGenderWithParamMap(paramMap);
    assertEquals(6, students.size());
}

5、使用 JdbClient 执行更新操作

与查询一样,JdbcClient 也支持创建、更新和删除记录等数据库操作。与前面的章节类似,可以通过各种重载版本的 param() 和 params() 方法绑定参数。因此,这里不再赘述。

不过,在执行 INSERT、UPDATE 和 DELETE SQL 语句时,不调用 query() 方法,而是调用 update() 方法。

在 student 表中插入记录:

Integer insertWithSetParamWithNamedParamAndSqlType(Student student) {
    String sql = "INSERT INTO student (student_name, age, grade, gender, state)"
      + "VALUES (:name, :age, :grade, :gender, :state)";
    Integer noOfrowsAffected = this.jdbcClient.sql(sql)
      .param("name", student.getStudentName(), Types.VARCHAR)
      .param("age", student.getAge(), Types.INTEGER)
      .param("grade", student.getGrade(), Types.INTEGER)
      .param("gender", student.getStudentGender(), Types.VARCHAR)
      .param("state", student.getState(), Types.VARCHAR)
      .update();
    return noOfrowsAffected;
}

@Test
void givenJdbcClient_whenInsertWithNamedParamAndSqlType_thenSuccess() {
    Student student = getSampleStudent("Johny Dep", 8, 4, "Male", "New York");
    assertEquals(1, studentDao.insertWithSetParamWithNamedParamAndSqlType(student));
}

上述方法使用 param(String name, Object value, int sqlType) 绑定参数。它有一个额外的 sqlType 参数,用于指定参数的数据类型。最后,update() 方法还会返回受影响的行数。

在上述方法中,getSampleStudent() 返回一个 Student 对象。然后将 Student 对象传递给 insertWithSetParamWithNamedParamAndSqlType() 方法,在 student 表中创建一条新记录。

与 JdbcTemplate 一样,JdbcClient 也有 update(KeyHolder generatedKeyHolder) 方法,用于获取插入记录时生成的自增ID。

6、使用示例

// 按主键查询
public MyData findDataById(Long id) {
        return jdbcClient.sql("select * from my_data where id = ?")
                .params(id)
                .query(MyData.class)
                .single();
    }

// 自定义条件查询
public List<MyData> findDataByName(String name) {
        return jdbcClient.sql("select * from my_data where name = ?")
                .params(name)
                .query(MyData.class)
                .list();
    }

// 变量占位符查询
public Integer insertDataWithNamedParam(MyData myData) {
        Integer rowsAffected = jdbcClient.sql("insert into my_data values(:id,:name) ")
                .param("id", myData.id())
                .param("name", myData.name())
                .update();
        return rowsAffected;
    }

// Map变量查询
public List<MyData> findDataByParamMap(Map<String, ?> paramMap) {
        return jdbcClient.sql("select * from my_data where name = :name")
                .params(paramMap)
                .query(MyData.class)
                .list();
    }

// 当查询返回的结果不能简单的映射到一个类时,可以编写RowMapper,适用于SQL语句比较复杂的场景:
public List<MyData> findDataWithRowMapper() {
        return jdbcClient.sql("select * from my_data")
                .query((rs, rowNum) -> new MyData(rs.getLong("id"), rs.getString("name")))
                .list();
    }

// 查询记录数
public Integer countByName(String name) {
        return jdbcClient.sql("select count(*) from my_data where name = ?")
                .params(name)
                .query(Integer.class)
                .single();
    }

// 占位符插入
public Integer insertDataWithParam(MyData myData) {
        Integer rowsAffected = jdbcClient.sql("insert into my_data values(?,?) ")
                .param(myData.id())
                .param(myData.name())
                .update();
        return rowsAffected;
    }

// 命名参数插入
public Integer insertDataWithNamedParam(MyData myData) {
        Integer rowsAffected = jdbcClient.sql("insert into my_data values(:id,:name) ")
                .param("id", myData.id())
                .param("name", myData.name())
                .update();
        return rowsAffected;
    }

// 插入整个对象
public Integer insertDataWithObject(MyData myData) {
        Integer rowsAffected = jdbcClient.sql("insert into my_data values(:id,:name) ")
                .paramSource(myData)
                .update();
        return rowsAffected;
    }

到此这篇关于SpringBoot3.2新特性之JdbcClient的使用的文章就介绍到这了,更多相关SpringBoot JdbcClient内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • springboot 通过博途获取plc点位的数据代码实现

    springboot 通过博途获取plc点位的数据代码实现

    这篇文章主要介绍了springboot 通过博途获取plc点位的数据的代码实现,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-08-08
  • Springboot中拦截GET请求获取请求参数验证合法性核心方法

    Springboot中拦截GET请求获取请求参数验证合法性核心方法

    这篇文章主要介绍了Springboot中拦截GET请求获取请求参数验证合法性,在Springboot中创建拦截器拦截所有GET类型请求,获取请求参数验证内容合法性防止SQL注入,这种方法适用拦截get类型请求,需要的朋友可以参考下
    2023-08-08
  • Java Heap Dump简介及使用举例

    Java Heap Dump简介及使用举例

    文章详解了Java堆转储(HeapDump)的概念、核心内容、生成方法及分析工具,强调其在诊断内存泄漏、溢出中的关键作用,推荐使用JVM参数自动触发,并指出EclipseMAT为最强大分析工具,同时提醒注意性能影响和数据安全,感兴趣的朋友跟随小编一起看看吧
    2022-12-12
  • 在SpringBoot中如何使用HttpClient实现HTTP请求

    在SpringBoot中如何使用HttpClient实现HTTP请求

    本文介绍了如何使用Apache HttpClient来访问HTTP协议的资源,并提供了详细的使用示例,包括GET和POST请求的无参和有参调用
    2025-02-02
  • Java中string和int的互相转换问题

    Java中string和int的互相转换问题

    本文通过实例代码给大家详细介绍了Java中string和int的互相转换问题,感兴趣的朋友一起看看吧
    2017-10-10
  • 详解Mybatis(五)Mapper接口

    详解Mybatis(五)Mapper接口

    这篇文章主要介绍了Mybatis Mapper接口,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-04-04
  • java 实例化类详解及简单实例

    java 实例化类详解及简单实例

    这篇文章主要介绍了java 实例化类详解及简单实例的相关资料,需要的朋友可以参考下
    2017-03-03
  • 浅析java修饰符访问权限(动力节点Java学院整理)

    浅析java修饰符访问权限(动力节点Java学院整理)

    Java有四种访问权限,其中三种有访问权限修饰符,分别为private,public和protected,还有一种不带任何修饰符,下面通过本文给大家简单介绍下java修饰符访问权限相关知识,感兴趣的朋友一起学习吧
    2017-04-04
  • SpringBatch简单入门案例

    SpringBatch简单入门案例

    文章介绍了SpringBatch批处理框架的使用,包括其基本概念、优势、架构以及入门案例,通过简单的任务和数据库连接配置,展示了如何使用SpringBatch进行基本的批处理操作,感兴趣的朋友跟随小编一起看看吧
    2025-12-12
  • java compare compareTo方法区别详解

    java compare compareTo方法区别详解

    本文主要介绍了java compare compareTo方法区别,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-09-09

最新评论