最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

淺談Mybatis傳參類型如何確定

 更新時間:2021年10月27日 14:15:22   作者:一灰灰  
最近有小伙伴在討論#{}與${}的區(qū)別時,有提到#{}是用字符串進行替換,本文主要介紹了mapper接口中不同的參數(shù)類型,最終拼接sql中是如何進行替換的,感興趣的可以了解一下

最近有小伙伴在討論#{}與${}的區(qū)別時,有提到#{}是用字符串進行替換,就我個人的理解,它的主要作用是占位,最終替換的結(jié)果并不一定是字符串方式,比如我們傳參類型是整形時,最終拼接的sql,傳參講道理也應(yīng)該是整形,而不是字符串的方式

接下來我們來看一下,mapper接口中不同的參數(shù)類型,最終拼接sql中是如何進行替換的

I. 環(huán)境配置

我們使用SpringBoot + Mybatis + MySql來搭建實例demo

springboot: 2.2.0.RELEASE
mysql: 5.7.22

1. 項目配置

<dependencies>
    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>2.2.0</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>
</dependencies>

核心的依賴mybatis-spring-boot-starter,至于版本選擇,到mvn倉庫中,找最新的
另外一個不可獲取的就是db配置信息,appliaction.yml

spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/story?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
    username: root
    password:

2. 數(shù)據(jù)庫表

用于測試的數(shù)據(jù)庫

CREATE TABLE `money` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(20) NOT NULL DEFAULT '' COMMENT '用戶名',
  `money` int(26) NOT NULL DEFAULT '0' COMMENT '錢',
  `is_deleted` tinyint(1) NOT NULL DEFAULT '0',
  `create_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '創(chuàng)建時間',
  `update_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新時間',
  PRIMARY KEY (`id`),
  KEY `name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=551 DEFAULT CHARSET=utf8mb4;

測試數(shù)據(jù),主要是name字段,值為一個數(shù)字的字符串

INSERT INTO `money` (`id`, `name`, `money`, `is_deleted`, `create_at`, `update_at`)
VALUES
 (120, '120', 200, 0, '2021-05-24 20:04:39', '2021-09-27 19:21:40');

II. 傳參類型確定

本文忽略掉mybatis中的po、mapper接口、xml文件的詳情,有興趣的小伙伴可以直接查看最下面的源碼(或者查看之前的博文也可以)

1. 參數(shù)類型為整形

針對上面的case,定義一個根據(jù)name查詢數(shù)據(jù)的接口,但是這個name參數(shù)類型為整數(shù)
mapper接口:

/**
 * int類型,最終的sql中參數(shù)替換的也是int
 * @param name
 * @return
 */
List<MoneyPo> queryByName(@Param("name") Integer name);

對應(yīng)的xml文件如下

<select id="queryByName" resultMap="BaseResultMap">
    select * from money where `name` = #{name}
</select>

上面這個寫法非常常見了,我們現(xiàn)在的問題就是,傳參為整數(shù),那么最終的sql是 name = 120 還是 name = '120'呢?
那么怎么確定最終生成的sql是啥樣的呢?這里介紹一個直接輸出mysql執(zhí)行sql日志的方式
在mysql服務(wù)器上執(zhí)行下面兩個命令,開啟sql執(zhí)行日志

set global general_log = "ON";
show variables like 'general_log%';

當(dāng)我們訪問上面的接口之后,會發(fā)現(xiàn)最終發(fā)送給mysql的sql語句中,參數(shù)替換之后依然是整數(shù)

select * from money where `name` = 120

2. 指定jdbcType

在使用#{}, ${}時,有時也會看到除了參數(shù)之外,還會指定jdbcType,那么我們在xml中指定這個對最終的sql生成會有影響么?

<select id="queryByNameV2" resultMap="BaseResultMap">
    select * from money where `name` = #{name, jdbcType=VARCHAR} and 0=0
</select>

生成的sql如下

select * from money where `name` = 120 and 0=0

從實際的sql來看,這個jdbcType并沒有影響最終的sql參數(shù)拼接,那它主要是干嘛用呢?(它主要適用于傳入null時,類型轉(zhuǎn)換可能出現(xiàn)的異常)

3. 傳參類型為String

當(dāng)我們傳參類型為string時,最終的sql講道理應(yīng)該會帶上引號

/**
 * 如果傳入的參數(shù)類型為string,會自動帶上''
 * @param name
 * @return
 */
List<MoneyPo> queryByNameV3(@Param("name") String name);

對應(yīng)的xml

<select id="queryByNameV3" resultMap="BaseResultMap">
    select * from money where `name` = #{name, jdbcType=VARCHAR} and 1=1
</select>

上面這個最終生成的sql如下
select * from money where `name` = '120' and 1=1

4. TypeHandler實現(xiàn)參數(shù)替換強制添加引號

看完上面幾節(jié),基本上可以有一個得出一個簡單的推論(當(dāng)然對不對則需要從源碼上分析了)

sql參數(shù)替換,最終并不是簡單使用字符串來替換,實際上是由參數(shù)java的參數(shù)類型決定,若java參數(shù)類型為字符串,拼接的sql為字符串格式;傳參為整型,拼接的sql也是整數(shù)

那么問題來了,為什么要了解這個?

關(guān)鍵點在于索引失效的問題

比如本文實例中的name上添加了索引,當(dāng)我們的sql是 select * from money where name = 120 會走不了索引,如果想走索引,要求傳入的參數(shù)必須是字符串,不能出現(xiàn)隱式的類型轉(zhuǎn)換

基于此,我們就有一個應(yīng)用場景了,為了避免由于傳參類型問題,導(dǎo)致走不了索引,我們希望name的傳參,不管實際傳入?yún)?shù)類型是什么,最終拼接的sql,都是字符串的格式;

我們借助自定義的TypeHandler來實現(xiàn)這個場景

@MappedTypes(value = {Long.class, Integer.class})
@MappedJdbcTypes(value = {JdbcType.CHAR, JdbcType.VARCHAR, JdbcType.LONGVARCHAR})
public class StrTypeHandler extends BaseTypeHandler<Object> {

    /**
     * java 類型轉(zhuǎn) jdbc類型
     *
     * @param ps
     * @param i
     * @param parameter
     * @param jdbcType
     * @throws SQLException
     */
    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType) throws SQLException {
        ps.setString(i, String.valueOf(parameter));
    }

    /**
     * jdbc類型轉(zhuǎn)java類型
     *
     * @param rs
     * @param columnName
     * @return
     * @throws SQLException
     */
    @Override
    public Object getNullableResult(ResultSet rs, String columnName) throws SQLException {
        return rs.getString(columnName);
    }

    @Override
    public Object getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        return rs.getString(columnIndex);
    }

    @Override
    public Object getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        return cs.getString(columnIndex);
    }
}

然后在xml中,指定TypeHandler

/**
 * 通過自定義的 TypeHandler 來實現(xiàn) java <-> jdbc 類型的互轉(zhuǎn),從而實現(xiàn)即時傳入的是int/long,也會轉(zhuǎn)成String
 * @param name
 * @return
 */
List<MoneyPo> queryByNameV4(@Param("name") Integer name);
<select id="queryByNameV4" resultMap="BaseResultMap">
    select * from money where `name` = #{name, jdbcType=VARCHAR, typeHandler=com.git.hui.boot.mybatis.handler.StrTypeHandler} and 2=2
</select>

上面這種寫法輸出的sql就會攜帶上單引號,這樣就可以從源頭上解決傳參類型不對,導(dǎo)致最終走不了索引的問題

select * from money where `name` = '120' and 2=2

5. 小結(jié)

本文通過一個簡單的實例,來測試Mapper接口中,不同的參數(shù)類型,對最終的sql生成的影響

參數(shù)類型為整數(shù)時,最終的sql的參數(shù)替換也是整數(shù)(#{}并不是簡單的字符串替換哦)
參數(shù)類型為字符串時,最終的sql參數(shù)替換,會自動攜帶'' (${}注意它不會自動帶上單引號,需要自己手動添加)

當(dāng)我們希望不管傳參什么類型,最終生成的sql,都是字符串替換時,可以借助自定義的TypeHandler來實現(xiàn),這樣可以從源頭上避免因為隱式類型轉(zhuǎn)換導(dǎo)致走不了索引問題
最后疑問來了,上面的結(jié)論靠譜么?mybatis中最終的sql是在什么地方拼接的?這個sql拼接的流程是怎樣的呢?
關(guān)于sql的拼接全流程,后續(xù)博文即將上線,我是一灰灰,走過路過的各位大佬幫忙點個贊、價格收藏、給個評價唄

 到此這篇關(guān)于Mybatis傳參類型如何確定的文章就介紹到這了,更多相關(guān)Mybatis傳參類型如何確定內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java生成指定范圍隨機數(shù)的多種代碼

    java生成指定范圍隨機數(shù)的多種代碼

    今天在寫代碼的時候需要用到一個生成指定范圍隨機數(shù)的函數(shù),百度了一下,發(fā)現(xiàn)了很多種方法,這里簡單為大家整理一下,方便需要的朋友
    2017-08-08
  • JavaFX實現(xiàn)簡易時鐘效果

    JavaFX實現(xiàn)簡易時鐘效果

    這篇文章主要為大家詳細介紹了JavaFX實現(xiàn)簡易時鐘效果,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-11-11
  • 據(jù)說這個是可以擼到2089年的idea2020.2(推薦)

    據(jù)說這個是可以擼到2089年的idea2020.2(推薦)

    這篇文章主要介紹了據(jù)說這個是可以擼到2089年的idea2020.2,本教程給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-09-09
  • 一文帶你深入理解Java?AbstractQueuedSynchronizer

    一文帶你深入理解Java?AbstractQueuedSynchronizer

    在并發(fā)編程中,鎖是一種保證線程安全的方式,這篇文章主要為大家介紹了AbstractQueuedSynchronizer(AQS)的數(shù)據(jù)結(jié)構(gòu)及實現(xiàn)原理,感興趣的小伙伴可以了解一下
    2023-07-07
  • Java map集合順序如何同步添加順序

    Java map集合順序如何同步添加順序

    這篇文章主要介紹了Java map集合順序如何同步添加順序,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-04-04
  • Java模擬HTTP Get Post請求 輕松實現(xiàn)校園BBS自動回帖

    Java模擬HTTP Get Post請求 輕松實現(xiàn)校園BBS自動回帖

    這篇文章主要介紹了Java模擬HTTP Get Post請求,輕松實現(xiàn)校園BBS自動回帖,感興趣的小伙伴們可以參考一下
    2015-12-12
  • Java基礎(chǔ)之集合Set詳解

    Java基礎(chǔ)之集合Set詳解

    這篇文章主要介紹了Java基礎(chǔ)之集合Set詳解,文中有非常詳細的代碼示例,對正在學(xué)習(xí)java基礎(chǔ)的小伙伴們有很好地幫助,需要的朋友可以參考下
    2021-05-05
  • MyBatisPlus 主鍵策略的實現(xiàn)(4種)

    MyBatisPlus 主鍵策略的實現(xiàn)(4種)

    MyBatis Plus 集成了多種主鍵策略,幫助用戶快速生成主鍵,本文主要介紹了MyBatisPlus主鍵策略的實現(xiàn),具有一定的參考價值,感興趣的可以了解一下
    2023-10-10
  • java多線程之線程安全的單例模式

    java多線程之線程安全的單例模式

    這篇文章主要為大家詳細介紹了java多線程之線程安全的單例模式,文章內(nèi)容全面,感興趣的小伙伴們可以參考一下
    2016-03-03
  • java開發(fā)微信公眾號支付

    java開發(fā)微信公眾號支付

    這篇文章主要給大家結(jié)合微信支付接口開發(fā)的實踐,從獲取用戶授權(quán)到各主要接口的使用方法等方面介紹微信支付的關(guān)鍵點技術(shù),有需要的小伙伴可以參考下
    2015-08-08

最新評論

阳城县| 石屏县| 万载县| 拉萨市| 莎车县| 临武县| 马山县| 历史| 五华县| 西贡区| 三江| 延长县| 休宁县| 安国市| 贵定县| 呼伦贝尔市| 花莲市| 河池市| 永安市| 普安县| 元朗区| 武山县| 徐汇区| 镇平县| 孝义市| 洛宁县| 金堂县| 南昌县| 济南市| 应城市| 天峨县| 饶河县| 西峡县| 探索| 深州市| 东乌珠穆沁旗| 宜黄县| 汽车| 子洲县| 通江县| 正安县|