日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

spring boot- JdbcTemplate、NamedParameterJdbcTemplate基本使用(批量更新插入)

發(fā)布時間:2024/3/26 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 spring boot- JdbcTemplate、NamedParameterJdbcTemplate基本使用(批量更新插入) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

文章目錄

  • 第一部分:JdbcTemplate
    • 一、了解JdbcTemplate
    • 二、JdbcTemplate使用步驟
      • 1. sql直接插入一條數(shù)據(jù)
      • 2. 通過Statement方式批量插入【推薦】
        • 批量導(dǎo)入 batchUpdate(String sql, BatchPreparedStatementSetter pss)
      • 3. 通過Statement方式批量更新
    • 三、JDBC連接URL中的配置參數(shù)(注意配置)
    • 四、jdbctemplate 打印sql配置
    • 五、參考
  • 第二部分: NamedParameterJdbcTemplate
    • 一、查詢返回結(jié)果映射到自定義類型
      • 使用demo舉例
    • 二、queryForList使用時注意事項
  • 第三部分:工作中常見問題整理
    • queryForObject方法返回結(jié)果為空會報錯
  • 相關(guān)參考

第一部分:JdbcTemplate

我們開發(fā)DAO層時用的最多的就是ORM框架(Mybatis,hibernate)了。在有些特殊的情況下,ORM框架的搭建略顯笨重,這時最好的選擇就是Spring中的jdbcTemplate了。

一、了解JdbcTemplate

? JDBC已經(jīng)能夠滿足大部分用戶最基本的需求,但是在使用JDBC時,必須自己來管理數(shù)據(jù)庫資源如:獲取PreparedStatement,設(shè)置SQL語句參數(shù),關(guān)閉連接等步驟。

JdbcTemplate是Spring對JDBC的封裝,目的是使JDBC更加易于使用。JdbcTemplate是Spring的一部分。JdbcTemplate處理了資源的建立和釋放。他幫助我們避免一些常見的錯誤,比如忘了總要關(guān)閉連接。他運行核心的JDBC工作流,如Statement的建立和執(zhí)行,而我們只需要提供SQL語句和提取結(jié)果。

JdbcTemplate是原生JDBC的更高一級別的工具性質(zhì)的操作類,對原生JDBC進(jìn)行了很多細(xì)節(jié)上的封裝,只提供了入口API,使用者只需要選對API然后傳對應(yīng)的參數(shù)即可;將原有的比較繁瑣的細(xì)節(jié)實現(xiàn)屏蔽了,對于使用的角度來說,表現(xiàn)得更加的友好;

jdbcTemplate提供的主要方法:

  • execute方法:可以用于執(zhí)行任何SQL語句,一般用于執(zhí)行DDL語句;
  • update方法及batchUpdate方法:update方法用于執(zhí)行新增、修改、刪除等語句;batchUpdate方法用于執(zhí)行批處理相關(guān)語句;
  • query方法及queryForXXX方法:用于執(zhí)行查詢相關(guān)語句;
  • call方法:用于執(zhí)行存儲過程、函數(shù)相關(guān)語句。

二、JdbcTemplate使用步驟

  • 項目工程是Maven整合SpringBoot2.x進(jìn)行開發(fā)的,所以默認(rèn)整合了JDBCTemplate, 直接注入導(dǎo)包即可:

1. sql直接插入一條數(shù)據(jù)

組裝sql,直接調(diào)用jdbcTemPlate的API即可

private boolean insertBySql() {// 簡單的sql執(zhí)行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可以指定參數(shù)類型,這種插入方式更加安全,有兩種常見的方式,注意設(shè)置參數(shù)時,起始值為1,而不是通常說的0

批量導(dǎo)入 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();}});}

批量導(dǎo)入注意點:

  • sql不要 分號";" 結(jié)尾,否則執(zhí)行報錯。它的原理是要字符串連接你這個sql。
  • getBatchSize 傳進(jìn)來list大小,setValues里面,根據(jù)列表.get(i)獲取列表當(dāng)前遍歷的實體類。
  • 返回的int[] it .但是里面的值都是-2 ,-2表示成功。沒有具體的行數(shù)。

    但是從目前測試來看,一條成功,就返回-2, 那么可以用it.length() 記錄插入成功多少條記錄。
    例如,返回結(jié)果如: [-2,-2,-2] 代碼3條成功!

    3. 通過Statement方式批量更新

    使用 JdbcTemplate BATCHUPDATE()方法來執(zhí)行批量插入操作。用這種方法,該語句只被編譯一次,執(zhí)行多次。

    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 {//注意設(shè)置參數(shù)時,起始值為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);}

    如果需要大量更新數(shù)據(jù),并且使用的jdbc driver支持batchUpdate的情況下,使用batchUpdate會比直接執(zhí)行逐行執(zhí)行update效率快一個數(shù)量級。但如果jdbc不支持batchUpdate,那么jdbcTemplate的batchUpdate在其內(nèi)部仍然是逐行執(zhí)行。

    我使用postgreSQL進(jìn)行試驗:

    當(dāng)需要插入1000個People時,逐行插入需要4秒,使用batchUpdate需要時間不到1秒

    當(dāng)需要插入10000個People時,逐行插入需要17秒,使用batchUpdate僅僅需要1秒

    三、JDBC連接URL中的配置參數(shù)(注意配置)

    db mysql / mysql cluster 5.7.19 / useServerPrepStmts / cachePrepStmts
    參考URL: https://www.cnblogs.com/lindows/p/13373347.html

    JDBC連接URL中的這些參數(shù)可以對批處理語句的速度產(chǎn)生很大影響 – 根據(jù)我的經(jīng)驗,它們可以加快速度:

  • 增加批量寫的速度:
    useServerPrepStmts=false
    rewriteBatchedStatements=true
    useCompression=true
  • 增加讀的速度:
    useServerPrepStmts=true
    cachePrepStmts=true
  • 1)useCompression=true,壓縮數(shù)據(jù)傳輸,優(yōu)化客戶端和MySQL服務(wù)器之間的通信性能。
    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 關(guān)閉服務(wù)器端編譯,sql語句在客戶端編譯好再發(fā)送給服務(wù)器端,發(fā)送語句如上。

    如果為true,sql會采用占位符方式發(fā)送到服務(wù)器端,在服務(wù)器端再組裝sql語句。
    占位符方式:INSERT INTO t (c1,c2) VALUES (?,?),(?,?),(?,?);

    當(dāng)然我們的目的是為了提高數(shù)據(jù)庫寫速度,所以當(dāng)rewriteBatchedStatements =true時useServerPrepStmts=false必須配合使用。

    四、jdbctemplate 打印sql配置

    之前用mybaties打印語句很好配置,后來用了JdbcTemplate就不知道怎么打印了,其實JdbcTemplate執(zhí)行sql語句的過程會做打印sql語句的操作,只不過我們的日志級別沒有設(shè)置為debug,將自己的日志級別設(shè)置為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之?dāng)?shù)據(jù)插入使用姿勢詳解
    參考URL: https://blog.csdn.net/liuyueyi25/article/details/89470146
    使用Spring jdbcTemplate的insertOrUpdate操作的最佳實踐是什么?
    參考URL: https://www.thinbug.com/q/22941655

    第二部分: NamedParameterJdbcTemplate

    在經(jīng)典的 JDBC 用法中, SQL 參數(shù)是用占位符 ? 表示,并且受到位置的限制. 定位參數(shù)的問題在于, 一旦參數(shù)的順序發(fā)生變化, 就必須改變參數(shù)綁定.

    在 Spring JDBC 框架中, 綁定 SQL 參數(shù)的另一種選擇是使用具名參數(shù)(named parameter).

    那么什么是具名參數(shù)?
    具名參數(shù): SQL 按名稱(以冒號開頭)而不是按位置進(jìn)行指定. 具名參數(shù)更易于維護(hù), 也提升了可讀性. 具名參數(shù)由框架類在運行時用占位符取代
    具名參數(shù)只在 NamedParameterJdbcTemplate 中得到支持。NamedParameterJdbcTemplate可以使用全部jdbcTemplate方法

    NamedParameterJdbcTemplate類拓展了JdbcTemplate類,對JdbcTemplate類進(jìn)行了封裝從而支持命名參數(shù)特性。

    NamedParameterJdbcTemplate主要提供以下三類方法:execute方法、query及queryForXXX方法、update及batchUpdate方法。

    總結(jié):
    開發(fā)中盡量使用NamedParameterJdbcTemplate代替JdbcTemplate,如果想使用JdbcTemplate,也可以通過NamedParameterJdbcTemplate#getJdbcOperations()獲取。
    不建議使用查詢結(jié)構(gòu)為Map的API。

    一、查詢返回結(jié)果映射到自定義類型

    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 = ?"; // 獲取結(jié)果 list = jdbcTemplate.query(sql, new Object[]{age}, new BeanPropertyRowMapper<User>(User.class));

    其中new Object[]{age}為條件查詢,如果查詢?nèi)?#xff0c;該字段可以去掉。

    使用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同樣也不能這么使用,而是應(yīng)該添加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方法返回結(jié)果為空會報錯

    關(guān)于queryqueryForObject方法返回結(jié)果為空會報錯及解決方法
    參考URL: https://www.pianshen.com/article/65121091946/

    問題描述:
    問題demo1:
    返回的結(jié)果是空給我拋了一個異常。

    問題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);

    當(dāng)count 搭配group by時,group by 沒有查到一個分組時,count的結(jié)果就是null。 此時我們queryForObject(sql, sqlParam, Long.class)方法時就會報錯。

    問題原因:
    返回的結(jié)果是空給我拋了一個異常。

    解決方法:
    針對問題demo2,修改sql。 理解其sql,其實它想統(tǒng)計兩表聯(lián)合查詢后不同 product_name 的個數(shù)。因此 我們 distinct b.product_name 之后,對其進(jìn)行count 就行。

    select count(distinct b.product_name) as total from t_product_code_mapping a, t_asset_info bwhere a.account_id=8and a.service_code = b.service_code

    相關(guān)參考

    詳解jdbcTemplate和namedParameterJdbcTemplate
    參考URL: https://www.jianshu.com/p/1bdc0e26a7e4
    NamedParameterJdbcTemplate常用方法總結(jié)
    參考URL: https://blog.csdn.net/u011179993/article/details/74791304
    Spring的NamedParameterJdbcTemplate使用方法小結(jié)以及項目實戰(zhàn)實例
    參考URL: https://blog.csdn.net/Jaiaxn/article/details/87889550

    總結(jié)

    以上是生活随笔為你收集整理的spring boot- JdbcTemplate、NamedParameterJdbcTemplate基本使用(批量更新插入)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。