MyBatis踩坑之单字符条件比较

背景

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 = ?
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章