SpringBoot3.2新特性之JdbcClient的使用
一、簡介
Spring 6.1 中新添加了 JdbcClient 接口,它提供了 Fluent 風(fēng)格的 API,統(tǒng)一了 JdbcTemplate 和 NamedParameterJdbcTemplate 的 Facade,支持鏈?zhǔn)讲僮鳌?/p>
有了 JdbcClient 后就可以使用 Fluent 風(fēng)格的 API 定義查詢、設(shè)置參數(shù)以及執(zhí)行數(shù)據(jù)庫操作了。
該功能簡化了 JDBC 操作,使其更易讀、更易懂。然而,對于 JDBC 批處理操作和存儲過程的調(diào)用,仍然需要使用 JdbcTemplate 和 NamedParameterJdbcTemplate 類。
SpringBoot3.2中也集成了JdbcClient ,配置也很簡單,只要引入相關(guān)包,Spring Boot 框架會自動發(fā)現(xiàn) application.properties 中的 DB 連接屬性,并在應(yīng)用啟動時(shí)創(chuàng)建 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、支持隱式位置參數(shù)
使用占位符 ? 來通過位置綁定 SQL 參數(shù)。
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());
}
在上述方法中,參數(shù) grade、state 和 gender 是按照方法 param() 的調(diào)用順序隱式注冊的。最后,當(dāng)調(diào)用 query() 方法時(shí),語句將被執(zhí)行,并通過 RowMapper 轉(zhuǎn)換、獲取結(jié)果,和 JdbcTemplate 一樣。
query() 方法還支持 ResultSetExtractor 和 RowCallbackHandler 參數(shù)。
在調(diào)用 list() 方法之前,不會檢索到任何結(jié)果。此外,還支持其他獲取結(jié)果的操作,如 optional()、set()、single() 和 stream()。
還可以通過 params 方法使用可變參數(shù)來設(shè)置 SQL 參數(shù):
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() 方法,后者使用可變參數(shù)。最后通過 single() 方法來檢索一條記錄。
params() 方法還有一個(gè)重載版本,可以接收一個(gè)參數(shù) 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、通過索引設(shè)置位置參數(shù)
如果需要設(shè)置 SQL 語句參數(shù)的位置,可以使用 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());
}
在該方法中,明確指定了參數(shù)的位置。此外,還使用了 query(ResultSetExtractor rse) 方法。
3、支持 Name / Value 對命名參數(shù)
JdbcClient 還支持使用占位符 : 綁定命名的 SQL 語句參數(shù),這是 NamedParameterJdbcTemplate 的特性。
param() 方法也可以設(shè)置鍵值對類型的參數(shù):
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);
}
在上述方法中,使用了命名參數(shù)。此外,還使用了 query(RowCallbackHandler rch) 方法來獲取結(jié)果。
4、通過 Map 設(shè)置命名參數(shù)
也可以通過 params(Map<String,?> paramMap) 方法,使用 Map 對象來設(shè)置命名參數(shù):
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 執(zhí)行更新操作
與查詢一樣,JdbcClient 也支持創(chuàng)建、更新和刪除記錄等數(shù)據(jù)庫操作。與前面的章節(jié)類似,可以通過各種重載版本的 param() 和 params() 方法綁定參數(shù)。因此,這里不再贅述。
不過,在執(zhí)行 INSERT、UPDATE 和 DELETE SQL 語句時(shí),不調(diào)用 query() 方法,而是調(diào)用 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) 綁定參數(shù)。它有一個(gè)額外的 sqlType 參數(shù),用于指定參數(shù)的數(shù)據(jù)類型。最后,update() 方法還會返回受影響的行數(shù)。
在上述方法中,getSampleStudent() 返回一個(gè) Student 對象。然后將 Student 對象傳遞給 insertWithSetParamWithNamedParamAndSqlType() 方法,在 student 表中創(chuàng)建一條新記錄。
與 JdbcTemplate 一樣,JdbcClient 也有 update(KeyHolder generatedKeyHolder) 方法,用于獲取插入記錄時(shí)生成的自增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();
}
// 當(dāng)查詢返回的結(jié)果不能簡單的映射到一個(gè)類時(shí),可以編寫RowMapper,適用于SQL語句比較復(fù)雜的場景:
public List<MyData> findDataWithRowMapper() {
return jdbcClient.sql("select * from my_data")
.query((rs, rowNum) -> new MyData(rs.getLong("id"), rs.getString("name")))
.list();
}
// 查詢記錄數(shù)
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;
}
// 命名參數(shù)插入
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;
}
// 插入整個(gè)對象
public Integer insertDataWithObject(MyData myData) {
Integer rowsAffected = jdbcClient.sql("insert into my_data values(:id,:name) ")
.paramSource(myData)
.update();
return rowsAffected;
}
到此這篇關(guān)于SpringBoot3.2新特性之JdbcClient的使用的文章就介紹到這了,更多相關(guān)SpringBoot JdbcClient內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
springboot?通過博途獲取plc點(diǎn)位的數(shù)據(jù)代碼實(shí)現(xiàn)
這篇文章主要介紹了springboot?通過博途獲取plc點(diǎn)位的數(shù)據(jù)的代碼實(shí)現(xiàn),本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-08-08
Springboot中攔截GET請求獲取請求參數(shù)驗(yàn)證合法性核心方法
這篇文章主要介紹了Springboot中攔截GET請求獲取請求參數(shù)驗(yàn)證合法性,在Springboot中創(chuàng)建攔截器攔截所有GET類型請求,獲取請求參數(shù)驗(yàn)證內(nèi)容合法性防止SQL注入,這種方法適用攔截get類型請求,需要的朋友可以參考下2023-08-08
在SpringBoot中如何使用HttpClient實(shí)現(xiàn)HTTP請求
本文介紹了如何使用Apache?HttpClient來訪問HTTP協(xié)議的資源,并提供了詳細(xì)的使用示例,包括GET和POST請求的無參和有參調(diào)用2025-02-02
淺析java修飾符訪問權(quán)限(動力節(jié)點(diǎn)Java學(xué)院整理)
Java有四種訪問權(quán)限,其中三種有訪問權(quán)限修飾符,分別為private,public和protected,還有一種不帶任何修飾符,下面通過本文給大家簡單介紹下java修飾符訪問權(quán)限相關(guān)知識,感興趣的朋友一起學(xué)習(xí)吧2017-04-04
java compare compareTo方法區(qū)別詳解
本文主要介紹了java compare compareTo方法區(qū)別,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-09-09

