SpringBoot高級篇JdbcTemplate之數據查詢上篇 講了如何使用JdbcTemplate進行簡單的查詢操做,主要介紹了三種方法的調用姿式 queryForMap
, queryForList
, queryForObject
本篇則繼續介紹剩下的兩種方法使用說明java
環境依然藉助前面一篇的配置,連接如: 190407-SpringBoot高級篇JdbcTemplate之數據插入使用姿式詳解git
或者直接查看項目源碼: github.com/liuyueyi/sp…github
咱們查詢所用數據,正是前面一篇插入的結果,以下圖spring
查詢上篇中介紹的三種方法,返回的記錄對應的結構要麼是map,要麼是經過RowMapper
進行結果封裝;而queryForRowSet
方法的調用,返回的則是SqlRowSet
對象,這是一個集合,也就是說,能夠查詢多條記錄sql
使用姿式也比較簡單,以下app
public void queryForRowSet() {
String sql = "select * from money where id > 1 limit 2";
SqlRowSet result = jdbcTemplate.queryForRowSet(sql);
while (result.next()) {
MoneyPO moneyPO = new MoneyPO();
moneyPO.setId(result.getInt("id"));
moneyPO.setName(result.getString("name"));
moneyPO.setMoney(result.getInt("money"));
moneyPO.setDeleted(result.getBoolean("is_deleted"));
moneyPO.setCreated(result.getDate("create_at").getTime());
moneyPO.setUpdated(result.getDate("update_at").getTime());
System.out.println("QueryForRowSet by DirectSql: " + moneyPO);
}
}
複製代碼
對於使用姿式而言與以前的區別不大,還有一種就是sql也支持使用佔位方式,如ide
// 採用佔位符方式查詢
sql = "select * from money where id > ? limit ?";
result = jdbcTemplate.queryForRowSet(sql, 1, 2);
while (result.next()) {
MoneyPO moneyPO = new MoneyPO();
moneyPO.setId(result.getInt("id"));
moneyPO.setName(result.getString("name"));
moneyPO.setMoney(result.getInt("money"));
moneyPO.setDeleted(result.getBoolean("is_deleted"));
moneyPO.setCreated(result.getDate("create_at").getTime());
moneyPO.setUpdated(result.getDate("update_at").getTime());
System.out.println("QueryForRowSet by ? sql: " + moneyPO);
}
複製代碼
重點關注下結果的處理,須要經過迭代器的方式進行數據遍歷,獲取每一列記錄的值的方式和前面同樣,能夠經過序號的方式獲取(序號從1開始),也能夠經過制定列名方式(db列名)spring-boot
對於query方法的使用,從不一樣的結果處理方式來看,劃分了四種,下面逐一說明測試
queryByCallBack
這種回調方式,query方法不返回結果,可是須要傳入一個回調對象,查詢到結果以後,會自動調用ui
private void queryByCallBack() {
String sql = "select * from money where id > 1 limit 2";
// 這個是回調方式,不返回結果;一條記錄回調一次
jdbcTemplate.query(sql, new RowCallbackHandler() {
@Override
public void processRow(ResultSet rs) throws SQLException {
MoneyPO moneyPO = result2po(rs);
System.out.println("queryByCallBack: " + moneyPO);
}
});
}
複製代碼
上面的實例代碼中,能夠看到回調方法中傳入一個ResultSet對象,簡單封裝一個轉換爲PO的方法
private MoneyPO result2po(ResultSet result) throws SQLException {
MoneyPO moneyPO = new MoneyPO();
moneyPO.setId(result.getInt("id"));
moneyPO.setName(result.getString("name"));
moneyPO.setMoney(result.getInt("money"));
moneyPO.setDeleted(result.getBoolean("is_deleted"));
moneyPO.setCreated(result.getDate("create_at").getTime());
moneyPO.setUpdated(result.getDate("update_at").getTime());
return moneyPO;
}
複製代碼
在後面的測試中,會看到上面會輸出兩行數據,也就是說
返回結果中每一條記錄都執行一次上面的回調方法,即返回n條數據,上面回調執行n次
ResultSetExtractor
前面回調方式主要針對的是不關係返回結果,這裏的則是將返回的結果,封裝成咱們預期的對象,而後返回
private void queryByResultSet() {
String sql = "select * from money where id > 1 limit 2";
// extractData 接收的是批量的結果,所以能夠理解爲一次對全部的結果進行轉換,能夠和 RowMapper 方式進行對比
List<MoneyPO> result = jdbcTemplate.query(sql, new ResultSetExtractor<List<MoneyPO>>() {
@Override
public List<MoneyPO> extractData(ResultSet rs) throws SQLException, DataAccessException {
List<MoneyPO> list = new ArrayList<>();
while (rs.next()) {
list.add(result2po(rs));
}
return list;
}
});
System.out.println("queryByResultSet: " + result);
}
複製代碼
額外注意下上面你的使用,若是返回的是多條數據,注意泛型參數類型爲List<?>
, 簡單來講這是一個對結果進行批量轉換的使用場景
所以在上面的extractData
方法調用時,傳入的是多條數據,須要本身進行迭代遍歷,而不能像第一種那樣使用
RowMapper
既然前面有批量處理,那固然也就有單行的轉換方式了,以下
private void queryByRowMapper() {
String sql = "select * from money where id > 1 limit 2";
// 若是返回的是多條數據,會逐一的調用 mapRow方法,所以能夠理解爲單個記錄的轉換
List<MoneyPO> result = jdbcTemplate.query(sql, new RowMapper<MoneyPO>() {
@Override
public MoneyPO mapRow(ResultSet rs, int rowNum) throws SQLException {
return result2po(rs);
}
});
System.out.println("queryByRowMapper: " + result);
}
複製代碼
在實際使用中,只須要記住RowMapper
方式傳入的是單條記錄,n次調用;而ResultSetExtractor
方式傳入的所有的記錄,1次調用
前面介紹的幾種都是直接寫sql,這固然不是推薦的寫法,更常見的是佔位sql,經過傳參替換,這類的使用前一篇博文介紹得比較多了,這裏給出一個簡單的演示
private void queryByPlaceHolder() {
String sql = "select * from money where id > ? limit ?";
// 佔位方式,在最後面加上實際的sql參數,第二個參數也能夠換成 ResultSetExtractor
List<MoneyPO> result = jdbcTemplate.query(sql, new RowMapper<MoneyPO>() {
@Override
public MoneyPO mapRow(ResultSet rs, int rowNum) throws SQLException {
return result2po(rs);
}
}, 1, 2);
System.out.println("queryByPlaceHolder: " + result);
}
複製代碼
PreparedStatement
方式在插入記錄的時候,PreparedStatement
這個咱們用得不少,特別是在要求返回主鍵id時,離不開它了, 在實際的查詢中,也是能夠這麼用的,特別是在使用PreparedStatementCreator
,咱們能夠設置查詢的db鏈接參數
private void queryByPreparedStatement() {
// 使用 PreparedStatementCreator查詢,主要是能夠設置鏈接相關參數, 如設置爲只讀
List<MoneyPO> result = jdbcTemplate.query(new PreparedStatementCreator() {
@Override
public PreparedStatement createPreparedStatement(Connection con) throws SQLException {
con.setReadOnly(true);
PreparedStatement statement = con.prepareStatement("select * from money where id > ? limit ?");
// 表示 id > 1
statement.setInt(1, 1);
// 表示 limit 2
statement.setInt(2, 2);
return statement;
}
}, new RowMapper<MoneyPO>() {
@Override
public MoneyPO mapRow(ResultSet rs, int rowNum) throws SQLException {
return result2po(rs);
}
});
System.out.println("queryByPreparedStatement: " + result);
}
複製代碼
上面是一個典型的使用case,固然在實際使用JdbcTemplate時,基本不這麼玩
前面一篇查詢中,在單個查詢中若是沒有結果命中sql,會拋出異常,那麼這裏呢?
private void queryNoRecord() {
// 沒有命中的狀況下,會怎樣
List<MoneyPO> result = jdbcTemplate
.query("select * from money where id > ? limit ?", new Object[]{100, 2}, new RowMapper<MoneyPO>() {
@Override
public MoneyPO mapRow(ResultSet rs, int rowNum) throws SQLException {
return result2po(rs);
}
});
System.out.println("queryNoRecord: " + result);
}
複製代碼
從後面的輸出結果會看出,沒有記錄命中時,並無什麼關係,上面會返回一個空集合
接下來測試下上面的輸出
package com.git.hui.boot.jdbc;
import com.git.hui.boot.jdbc.insert.InsertService;
import com.git.hui.boot.jdbc.query.QueryService;
import com.git.hui.boot.jdbc.query.QueryServiceV2;
import com.git.hui.boot.jdbc.update.UpdateService;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/** * Created by @author yihui in 11:04 19/4/4. */
@SpringBootApplication
public class Application {
private QueryServiceV2 queryServiceV2;
public Application(QueryServiceV2 queryServiceV2) {
this.queryServiceV2 = queryServiceV2;
queryTest2();
}
public void queryTest2() {
// 第三個調用
queryServiceV2.queryForRowSet();
queryServiceV2.query();
}
public static void main(String[] args) {
SpringApplication.run(Application.class);
}
}
複製代碼
上面執行輸出結果以下
本文主要介紹了另外兩種查詢姿式, queryForRowSet
與 query
queryForRowSet
SqlRowSet
對象,須要遍歷獲取全部的結果query
ResultSetExtractor
RowMapper
PreparedStatementCreator
來建立PreparedStatement
方式處理相關博文
盡信書則不如,以上內容,純屬一家之言,因我的能力有限,不免有疏漏和錯誤之處,如發現bug或者有更好的建議,歡迎批評指正,不吝感激