背景
Mybatis中可以使用 <choose><when>...</when></choose>
語句來實現條件選擇,<when>
標籤含有 test
屬性用於設置比較條件,但是在某些特定情況下,字符串的比較會存在一個坑,那就是單字符字符串會被降級爲字符類型(char),從而導致比較條件不會生效。
示例
假設有如下需求:用戶分爲個人賬戶和機構賬戶兩類,其中個人賬戶使用身份證註冊,機構用戶使用機構統一社會信用代碼註冊,某個功能需要提供根據用戶類型(個人/機構)以及對應的證件號碼查詢用戶信息。
1. 數據庫
CREATE TABLE `t_user` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '主鍵ID',
`username` varchar(50) NOT NULL COMMENT '用戶名',
`user_type` varchar(1) NOT NULL COMMENT '用戶類型(0-個人用戶,1-機構用戶)',
`user_id` varchar(18) DEFAULT NULL COMMENT '個人用戶身份證',
`org_id` varchar(18) DEFAULT NULL COMMENT '企業用戶機構代碼',
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '創建時間',
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新時間',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
2. 對應的MyBatis Mapper文件
<select id="getUser" resultMap="UserMap">
SELECT
<include refid="base_columns" />
FROM t_user
WHERE 1=1
AND user_type = #{userType,jdbcType=VARCHAR}
<choose>
<when test="userType == '0'">
AND user_id = #{userId,jdbcType=VARCHAR}
</when>
<when test="userType == '1'">
AND org_id = #{orgId,jdbcType=VARCHAR}
</when>
</choose>
</select>
接口調用:
User user = userMapper.getUser("0", "310109196509080012", null);
跑單元測試發現報錯:
org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.exceptions.TooManyResultsException: Expected one result (or null) to be returned by selectOne(), but found: 3
檢查SQL語句調用,發現 <when>
中定義的 AND 連接條件根本沒有生效:
SELECT id, username, user_type, user_id, org_id, create_time, update_time FROM t_user WHERE 1=1 AND user_type = ?
3. 解決方案
解決方案有兩種,一是把 <when>
中條件語句等號右邊的字符串改爲整數,二是把條件語句等號右邊的字符串加上 .toString()
方法調用。
修改後再次運行單元測試,測試通過,輸出的SQL語句如下:
SELECT id, username, user_type, user_id, org_id, create_time, update_time FROM t_user WHERE 1=1 AND user_type = ? AND user_id = ?