Backend Development 8 min read

Using Spring Boot 3.2 JdbcClient for Database Operations – Overview and Code Examples

This article introduces Spring Boot 3.2's new JdbcClient, explains its fluent API style, shows how to add the dependency, inject it, and perform various query and insert operations with code examples, highlighting its advantages over traditional ORM frameworks.

Code Ape Tech Column
Code Ape Tech Column
Code Ape Tech Column
Using Spring Boot 3.2 JdbcClient for Database Operations – Overview and Code Examples

Hello everyone, I am Chen.

Spring Boot 3.2 introduces a new JdbcClient for database operations, which wraps JdbcTemplate with a fluent API allowing chain calls.

Now Spring provides four ways to access databases: JdbcTemplate , JdbcClient , Spring Data JDBC , and Spring Data JPA . For scenarios where heavy ORM is unsuitable or complex SQL is needed, JdbcClient can be used, though it does not support batch operations or stored procedures, which still require JdbcTemplate .

1. Overview

JdbcClient is a lightweight database access framework that uses a fluent API, making it simple, flexible, easy to read and maintain, and capable of handling complex SQL.

2. Introducing JdbcClient

First, add the spring-data-jdbc dependency.

In build.gradle add:

implementation 'org.springframework.boot:spring-boot-starter-data-jdbc'

Then inject JdbcClient directly in a service:

@Component
public class DbService {
    @Autowired
    private JdbcClient jdbcClient;
}

3. Query Operations

With JdbcClient you can query by primary key or custom conditions.

Query by primary key:

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

Query by custom condition:

public List
findDataByName(String name) {
    return jdbcClient.sql("select * from my_data where name = ?")
                     .params(name)
                     .query(MyData.class)
                     .list();
}

You can also use named parameters:

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;
}

Or pass a Map of parameters:

public List
findDataByParamMap(Map
paramMap) {
    return jdbcClient.sql("select * from my_data where name = :name")
                     .params(paramMap)
                     .query(MyData.class)
                     .list();
}

For results that cannot be directly mapped, you can provide a RowMapper :

public List
findDataWithRowMapper() {
    return jdbcClient.sql("select * from my_data")
                     .query((rs, rowNum) -> new MyData(rs.getLong("id"), rs.getString("name")))
                     .list();
}

You can also query the record count:

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

4. Insert Data

Use the update method for inserts and updates.

Insert with positional parameters:

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

Insert with named parameters:

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;
}

Insert using an object as a parameter source:

public Integer insertDataWithObject(MyData myData) {
    Integer rowsAffected = jdbcClient.sql("insert into my_data values(:id,:name) ")
                                 .paramSource(myData)
                                 .update();
    return rowsAffected;
}

5. Summary

The examples demonstrate that most basic database operations can be performed with JdbcClient , avoiding the complexity of full ORM frameworks. Its fluent API style makes code easier to write and read.

Complete demonstration of database operations:

@Slf4j
@SpringBootApplication
public class Application implements CommandLineRunner {

    @Autowired
    private DbService dbService;

    @Override
    public void run(String... args) {
        MyData myData = new MyData(1L, "test");
        log.info("insert rows: {}", dbService.insertDataWithObject(myData));

        MyData myData2 = new MyData(2L, "test");
        dbService.insertDataWithParam(myData2);

        MyData myData3 = new MyData(3L, "author");
        dbService.insertDataWithNamedParam(myData3);

        log.info("findDataById: {}", dbService.findDataById(1L));
        log.info("findDataByName: {}", dbService.findDataByName("test"));
        log.info("findDataWithRowMapper: {}", dbService.findDataWithRowMapper());
        log.info("findDataByParamMap: {}", dbService.findDataByParamMap(Map.of("name", "author")));
        log.info("countByName: {}", dbService.countByName("test"));
    }

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

Final Note (Please Follow)

If this article helped you, please like, view, share, and bookmark—it motivates me to keep writing.

My knowledge community is open for a fee of 199 CNY, offering extensive resources such as the "Code Monkey Chronic Disease Cloud Management" project, Spring full‑stack series, massive data sharding practice, DDD micro‑service series, and more.

For more details, visit the links provided.

backendJavaDatabaseSpringBootFluentAPIJdbcClient
Code Ape Tech Column
Written by

Code Ape Tech Column

Former Ant Group P8 engineer, pure technologist, sharing full‑stack Java, job interview and career advice through a column. Site: java-family.cn

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.