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.
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.
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
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.