spring boot- JdbcTemplate、NamedParameterJdbcTemplate基本使用(批量更新插入)
文章目錄
- 第一部分:JdbcTemplate
- 一、了解JdbcTemplate
- 二、JdbcTemplate使用步驟
- 1. sql直接插入一條數據
- 2. 通過Statement方式批量插入【推薦】
- 批量導入 batchUpdate(String sql, BatchPreparedStatementSetter pss)
- 3. 通過Statement方式批量更新
- 三、JDBC連接URL中的配置參數(注意配置)
- 四、jdbctemplate 打印sql配置
- 五、參考
- 第二部分: NamedParameterJdbcTemplate
- 一、查詢返回結果映射到自定義類型
- 使用demo舉例
- 二、queryForList使用時注意事項
- 第三部分:工作中常見問題整理
- queryForObject方法返回結果為空會報錯
- 相關參考
第一部分:JdbcTemplate
我們開發DAO層時用的最多的就是ORM框架(Mybatis,hibernate)了。在有些特殊的情況下,ORM框架的搭建略顯笨重,這時最好的選擇就是Spring中的jdbcTemplate了。
一、了解JdbcTemplate
? JDBC已經能夠滿足大部分用戶最基本的需求,但是在使用JDBC時,必須自己來管理數據庫資源如:獲取PreparedStatement,設置SQL語句參數,關閉連接等步驟。
JdbcTemplate是Spring對JDBC的封裝,目的是使JDBC更加易于使用。JdbcTemplate是Spring的一部分。JdbcTemplate處理了資源的建立和釋放。他幫助我們避免一些常見的錯誤,比如忘了總要關閉連接。他運行核心的JDBC工作流,如Statement的建立和執行,而我們只需要提供SQL語句和提取結果。
JdbcTemplate是原生JDBC的更高一級別的工具性質的操作類,對原生JDBC進行了很多細節上的封裝,只提供了入口API,使用者只需要選對API然后傳對應的參數即可;將原有的比較繁瑣的細節實現屏蔽了,對于使用的角度來說,表現得更加的友好;
jdbcTemplate提供的主要方法:
- execute方法:可以用于執行任何SQL語句,一般用于執行DDL語句;
- update方法及batchUpdate方法:update方法用于執行新增、修改、刪除等語句;batchUpdate方法用于執行批處理相關語句;
- query方法及queryForXXX方法:用于執行查詢相關語句;
- call方法:用于執行存儲過程、函數相關語句。
二、JdbcTemplate使用步驟
- 項目工程是Maven整合SpringBoot2.x進行開發的,所以默認整合了JDBCTemplate, 直接注入導包即可:
1. sql直接插入一條數據
組裝sql,直接調用jdbcTemPlate的API即可
private boolean insertBySql() {// 簡單的sql執行String sql = "INSERT INTO `money` (`name`, `money`, `is_deleted`) VALUES ('一灰灰blog', 100, 0);";return jdbcTemplate.update(sql) > 0; }不推薦這種使用方式,不安全!
2. 通過Statement方式批量插入【推薦】
jdbctemplate的batchUpdate使用方法
參考URL: https://www.cnblogs.com/rookie-ray/p/11790612.html
通過Statement可以指定參數類型,這種插入方式更加安全,有兩種常見的方式,注意設置參數時,起始值為1,而不是通常說的0
批量導入 batchUpdate(String sql, BatchPreparedStatementSetter pss)
public int[] batchInsert(List<Book> books) {return this.jdbcTemplate.batchUpdate("insert into books (name, price) values(?,?)",new BatchPreparedStatementSetter() {@Overridepublic void setValues(PreparedStatement ps, int i) throws SQLException { ps.setString(1, books.get(i).getName());ps.setBigDecimal(2, books.get(i).getPrice());}@Overridepublic int getBatchSize() {return books.size();}});}批量導入注意點:
返回的int[] it .但是里面的值都是-2 ,-2表示成功。沒有具體的行數。
但是從目前測試來看,一條成功,就返回-2, 那么可以用it.length() 記錄插入成功多少條記錄。
例如,返回結果如: [-2,-2,-2] 代碼3條成功!
3. 通過Statement方式批量更新
使用 JdbcTemplate BATCHUPDATE()方法來執行批量插入操作。用這種方法,該語句只被編譯一次,執行多次。
public void batchUpdateByStatement(List<UserPO> updateList) {logger.info("batchUpdateByStatement start! ");String sql = "UPDATE user_check set name=?, code=? where mobile=?";int[] ans = jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() {@Overridepublic void setValues(PreparedStatement preparedStatement, int i) throws SQLException {//注意設置參數時,起始值為1,而不是通常說的0preparedStatement.setString(1, updateList.get(i).getName());preparedStatement.setString(2, updateList.get(i).getCode());preparedStatement.setString(3, updateList.get(i).getMobile());}@Overridepublic int getBatchSize() {return updateList.size();}});logger.info("batchUpdateByStatement success update db size: {}", ans.length);}如果需要大量更新數據,并且使用的jdbc driver支持batchUpdate的情況下,使用batchUpdate會比直接執行逐行執行update效率快一個數量級。但如果jdbc不支持batchUpdate,那么jdbcTemplate的batchUpdate在其內部仍然是逐行執行。
我使用postgreSQL進行試驗:
當需要插入1000個People時,逐行插入需要4秒,使用batchUpdate需要時間不到1秒
當需要插入10000個People時,逐行插入需要17秒,使用batchUpdate僅僅需要1秒
三、JDBC連接URL中的配置參數(注意配置)
db mysql / mysql cluster 5.7.19 / useServerPrepStmts / cachePrepStmts
參考URL: https://www.cnblogs.com/lindows/p/13373347.html
JDBC連接URL中的這些參數可以對批處理語句的速度產生很大影響 – 根據我的經驗,它們可以加快速度:
useServerPrepStmts=false
rewriteBatchedStatements=true
useCompression=true
useServerPrepStmts=true
cachePrepStmts=true
1)useCompression=true,壓縮數據傳輸,優化客戶端和MySQL服務器之間的通信性能。
2)rewriteBatchedStatements=true ,開啟批量寫功能
將會使大批量單條插入語句:
INSERT INTO t (c1,c2) VALUES (‘One’,1);
INSERT INTO t (c1,c2) VALUES (‘Two’,2);
INSERT INTO t (c1,c2) VALUES (‘Three’,3);
改寫成真正的批量插入語句:
INSERT INTO t (c1,c2) VALUES (‘One’,1),(‘Two’,2),(‘Three’,3);
3)useServerPrepStmts=false 關閉服務器端編譯,sql語句在客戶端編譯好再發送給服務器端,發送語句如上。
如果為true,sql會采用占位符方式發送到服務器端,在服務器端再組裝sql語句。
占位符方式:INSERT INTO t (c1,c2) VALUES (?,?),(?,?),(?,?);
當然我們的目的是為了提高數據庫寫速度,所以當rewriteBatchedStatements =true時useServerPrepStmts=false必須配合使用。
四、jdbctemplate 打印sql配置
之前用mybaties打印語句很好配置,后來用了JdbcTemplate就不知道怎么打印了,其實JdbcTemplate執行sql語句的過程會做打印sql語句的操作,只不過我們的日志級別沒有設置為debug,將自己的日志級別設置為debug就可以了
logging:level:org.springframework.jdbc.core.JdbcTemplate: DEBUG或
logging.level.org.springframework.jdbc.core.JdbcTemplate=DEBUG五、參考
JdbcTemplate基本使用
參考URL: https://blog.csdn.net/weixin_40001125/article/details/88538576
SpringBoot高級篇JdbcTemplate之數據插入使用姿勢詳解
參考URL: https://blog.csdn.net/liuyueyi25/article/details/89470146
使用Spring jdbcTemplate的insertOrUpdate操作的最佳實踐是什么?
參考URL: https://www.thinbug.com/q/22941655
第二部分: NamedParameterJdbcTemplate
在經典的 JDBC 用法中, SQL 參數是用占位符 ? 表示,并且受到位置的限制. 定位參數的問題在于, 一旦參數的順序發生變化, 就必須改變參數綁定.
在 Spring JDBC 框架中, 綁定 SQL 參數的另一種選擇是使用具名參數(named parameter).
那么什么是具名參數?
具名參數: SQL 按名稱(以冒號開頭)而不是按位置進行指定. 具名參數更易于維護, 也提升了可讀性. 具名參數由框架類在運行時用占位符取代
具名參數只在 NamedParameterJdbcTemplate 中得到支持。NamedParameterJdbcTemplate可以使用全部jdbcTemplate方法
NamedParameterJdbcTemplate類拓展了JdbcTemplate類,對JdbcTemplate類進行了封裝從而支持命名參數特性。
NamedParameterJdbcTemplate主要提供以下三類方法:execute方法、query及queryForXXX方法、update及batchUpdate方法。
總結:
開發中盡量使用NamedParameterJdbcTemplate代替JdbcTemplate,如果想使用JdbcTemplate,也可以通過NamedParameterJdbcTemplate#getJdbcOperations()獲取。
不建議使用查詢結構為Map的API。
一、查詢返回結果映射到自定義類型
SpringMVC jdbcTemplate中queryForObject以及queryForList返回映射實體使用
參考URL: https://blog.csdn.net/fengshizty/article/details/43309055
使用BeanPropertyRowMapper + query方法返回自定義對象集合:
List<User> list = new ArrayList(); // 條件查詢 String sql = "SELECT * FROM USER WHERE AGE = ?"; // 獲取結果 list = jdbcTemplate.query(sql, new Object[]{age}, new BeanPropertyRowMapper<User>(User.class));其中new Object[]{age}為條件查詢,如果查詢全量,該字段可以去掉。
使用demo舉例
StringBuffer sqlBuffer = new StringBuffer();sqlBuffer.append("select * from user_info where id = :accountId ");MapSqlParameterSource sqlParam = new MapSqlParameterSource();sqlParam.addValue("accountId", accountId);BeanPropertyRowMapper<UserVO> rowMapper = new BeanPropertyRowMapper<>(UserVO.class);return jdbcTemplate.query(sqlBuffer.toString(), sqlParam, rowMapper);二、queryForList使用時注意事項
SpringBoot中使用JdbcTemplate中queryForList遇到的坑
參考URL: https://blog.csdn.net/HD243608836/article/details/99841903
SpringMVC jdbcTemplate中queryForObject以及queryForList返回映射實體使用
參考URL: https://blog.csdn.net/fengshizty/article/details/43309055
注意使用,使用queryForList只能返回基本類型的集合。
不僅是jdbcTemplate.queryForList不能這么使用,queryForObject同樣也不能這么使用,而是應該添加new RowMapper接口才能返回自定義的實體類對象。
使用queryForList返回基本類型的集合<以String為例>:
List<String> names = new ArrayList(); // sql語句,SUBSTR是SQL截取字段的方法, String sql = "SELECT DISTINCT SUBSTR(NAME, 2) FROM USER "; // 查詢,使用queryForList方法,返回基本類型 names = jdbcTemplate.queryForList(sql, String.class);注意:映射到自定義類型,我們可以用這個query,不是queryForList
//可以用這個(注意是query,不是queryForList) List<T> result = jdbcTemplate.query(sql.toString(), new Object[] {queryPara}, new BeanPropertyRowMapper<T>(T.class))第三部分:工作中常見問題整理
queryForObject方法返回結果為空會報錯
關于queryqueryForObject方法返回結果為空會報錯及解決方法
參考URL: https://www.pianshen.com/article/65121091946/
問題描述:
問題demo1:
返回的結果是空給我拋了一個異常。
問題demo2:
select count(b.product_name) from t_product_code_mapping a, t_asset_info bwhere a.account_id=6and a.service_code = b.service_codegroup by b.product_name namedJdbcTemplate.queryForObject(sql, sqlParam, Long.class);當count 搭配group by時,group by 沒有查到一個分組時,count的結果就是null。 此時我們queryForObject(sql, sqlParam, Long.class)方法時就會報錯。
問題原因:
返回的結果是空給我拋了一個異常。
解決方法:
針對問題demo2,修改sql。 理解其sql,其實它想統計兩表聯合查詢后不同 product_name 的個數。因此 我們 distinct b.product_name 之后,對其進行count 就行。
相關參考
詳解jdbcTemplate和namedParameterJdbcTemplate
參考URL: https://www.jianshu.com/p/1bdc0e26a7e4
NamedParameterJdbcTemplate常用方法總結
參考URL: https://blog.csdn.net/u011179993/article/details/74791304
Spring的NamedParameterJdbcTemplate使用方法小結以及項目實戰實例
參考URL: https://blog.csdn.net/Jaiaxn/article/details/87889550
總結
以上是生活随笔為你收集整理的spring boot- JdbcTemplate、NamedParameterJdbcTemplate基本使用(批量更新插入)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ubuntu ls -l 分屏显示
- 下一篇: EternalBlue永恒之蓝ms17_