原始碼解析之 Mybatis 對 Integer 引數做了什麼手腳?
阿新 • • 發佈:2021-03-11
---
title: 原始碼解析之 Mybatis 對 Integer 引數做了什麼手腳?
date: 2021-03-11
updated: 2021-03-11
categories:
- Mybatis
- 原始碼解析
tags:
- Mybatis
- 原始碼解析
---
解決方案放在第二節,急需解決問題,可直接檢視解決方案。
本文為深度長文,請耐心閱讀!
---
---
## 問題描述
在 Mybatis 中,Integer 的入參為 0 時,發現判斷條件的非空判斷沒有生效,原本應該存在的判斷條件丟失了。
那麼,Mybatis 到底對 Integer 引數做了什麼手腳呢?下面我們來舉例說明:
**環境示例**:
該問題只與 Mybatis 的實現機制有關,與版本基本無關(如果說相關性,可能只與原始碼中實現程式碼所在的行數有關)。
不過,為了養成良好的習慣,還是稍微提一下,我使用的 Mybatis 版本是 3.5.2。
**介面示例**:
```java
@GetMapping("/queryByAgeGroup")
public HttpStatus queryByAgeGroup(@RequestParams("ageGroup") Integer ageGroup) {
// ageGroup 年齡段:0 代表幼兒,1 代表青年,2 代表中年,3 代表老年,-1 代表未知
IndexTestService.queryByAgeGroup(ageGroup);
return HttpStatus.HTTP_OK;
}
```
測試用例屬於引數透傳,沒有業務邏輯,故省略 Service 和 Dao 層。
**查詢 SQL 示例**:
```xml
```
**資料表結構示例**:
```sql
CREATE TABLE `people_info` (
`id` varchar(64) NOT NULL COMMENT '主鍵',
`name` varchar(255) DEFAULT NULL COMMENT '名稱',
`age_group` int(11) DEFAULT NULL COMMENT '年齡',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
```
當入參為 0 時,
發現控制檯列印 SQL 如下:
```sql
select *
from `people_info`
where 1 = 1
-- 本該存在的 ageGroup 判斷消失了!
```
## 解決方案
首先提供該問題的幾種解決方案。
### 方案一
如果是資料字典型別的欄位,在定義資料字典時,避免使用 0 作為列舉值,從根源杜絕該問題。
### 方案二
如果是非法資料,可在 Controller 層入參增加引數校驗,如果傳 0,提示“引數無效”。
### 方案三
如果是合法資料,可在 SQL 判斷條件上增加 ` or ageGroup == 0` 判斷。
```xml
```
### 方案四
如果是合法資料,可將 Integer 轉為 String,按 String 引數處理。
```java
String ageGroupStr = String.valueOf(1);
```
## 原始碼解析
下面,我們就通過分析原始碼,一起來看一下 Mybatis 不為人知的“小動作”。
### 解析
1. 首先,讓我們來到 DefaultSqlSession#select(statement, parameter, rowBounds, handler) 方法。
```java
// 第 165 行
@Override
public void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {
try {
// 拿到對映的 sql 語句
MappedStatement ms = configuration.getMappedStatement(statement);
// 執行器執行查詢 sql -- 重點!!!
executor.query(ms, wrapCollection(parameter), rowBounds, handler);
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
```
2. 此時拿到傳入 sql,那麼有“小動作”的相想必是執行器,下面進入 BaseExecutor#query(ms, parameter, rowBounds, resultHandler) 方法。
```java
// 第 132 行
@Override