一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - 淺談Mybatis傳參類型如何確定

淺談Mybatis傳參類型如何確定

2022-03-03 00:31一灰灰 Java教程

最近有小伙伴在討論#{}與${}的區別時,有提到#{}是用字符串進行替換,本文主要介紹了mapper接口中不同的參數類型,最終拼接sql中是如何進行替換的,感興趣的可以了解一下

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

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

I. 環境配置

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

springboot: 2.2.0.RELEASE
mysql: 5.7.22

1. 項目配置

?
1
2
3
4
5
6
7
8
9
10
11
<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

?
1
2
3
4
5
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. 數據庫表

用于測試的數據庫

?
1
2
3
4
5
6
7
8
9
10
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 '創建時間',
  `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;

測試數據,主要是name字段,值為一個數字的字符串

?
1
2
3
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. 參數類型為整形

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

?
1
2
3
4
5
6
/**
 * int類型,最終的sql中參數替換的也是int
 * @param name
 * @return
 */
List<MoneyPo> queryByName(@Param("name") Integer name);

對應的xml文件如下

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

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

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

當我們訪問上面的接口之后,會發現最終發送給mysql的sql語句中,參數替換之后依然是整數

?
1
select * from money where `name` = 120

2. 指定jdbcType

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

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

生成的sql如下

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

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

3. 傳參類型為String

當我們傳參類型為string時,最終的sql講道理應該會帶上引號

?
1
2
3
4
5
6
/**
 * 如果傳入的參數類型為string,會自動帶上''
 * @param name
 * @return
 */
List<MoneyPo> queryByNameV3(@Param("name") String name);

對應的xml

?
1
2
3
<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實現參數替換強制添加引號

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

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

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

關鍵點在于索引失效的問題

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

基于此,我們就有一個應用場景了,為了避免由于傳參類型問題,導致走不了索引,我們希望name的傳參,不管實際傳入參數類型是什么,最終拼接的sql,都是字符串的格式;

我們借助自定義的TypeHandler來實現這個場景

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
@MappedTypes(value = {Long.class, Integer.class})
@MappedJdbcTypes(value = {JdbcType.CHAR, JdbcType.VARCHAR, JdbcType.LONGVARCHAR})
public class StrTypeHandler extends BaseTypeHandler<Object> {
 
    /**
     * java 類型轉 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類型轉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

?
1
2
3
4
5
6
/**
 * 通過自定義的 TypeHandler 來實現 java <-> jdbc 類型的互轉,從而實現即時傳入的是int/long,也會轉成String
 * @param name
 * @return
 */
List<MoneyPo> queryByNameV4(@Param("name") Integer name);
?
1
2
3
<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就會攜帶上單引號,這樣就可以從源頭上解決傳參類型不對,導致最終走不了索引的問題

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

5. 小結

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

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

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

 到此這篇關于Mybatis傳參類型如何確定的文章就介紹到這了,更多相關Mybatis傳參類型如何確定內容請搜索服務器之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持服務器之家!

原文鏈接:https://juejin.cn/post/7023341996232310814

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 国产精品日本亚洲777 | 麻豆网 | 国产免费丝袜调教视频 | 不良网站在线观看 | 拔插拔插8x8x海外华人免费视频 | 亚洲高清中文字幕精品不卡 | 关晓彤一级做a爰片性色毛片 | 女人特黄大aaaaaa大片 | 日韩精品亚洲专区在线影视 | 国产精品思瑞在线观看 | 国产福利免费看 | 草莓香蕉绿巨人丝瓜榴莲污在线观看 | 国产成人综合一区人人 | 四虎最新免费网址 | 美女张开腿黄网站免费精品动漫 | 日本一区二区视频免费播放 | 香蕉久久一区二区三区 | 香蕉草莓视频 | 国产精品露脸国语对白99 | 精品一区二区高清在线观看 | 青青草国产青春综合久久 | 亚洲精品一区二区三区中文字幕 | 久久全国免费观看视频 | 欧美日韩成人在线视频 | 国产色图片 | 亚洲 欧美 日本 国产 高清 | 四虎影视在线永久免费观看 | 美女口述又粗又大感觉 | 亚洲男人的天堂视频 | 91九色麻豆| 猫咪免费人成网站在线观看入口 | 亚洲国产成人久久午夜 | 亚洲品质水蜜桃 | 午夜性色一区二区三区不卡视频 | 亚洲精品乱码久久久久久蜜桃欧美 | 亚洲国产cao | 精品亚洲国产一区二区 | 欧美久在线观看在线观看 | 日韩在线 在线播放 | 成人免费淫片95视频观看网站 | 亚洲国产成人超福利久久精品 |