mybatis字段映射的容错性

本文通过一个实际的bug引出MyBatis在字段映射时的容错性问题。当数据库中CHAR类型的空字符串被查询时,MyBatis会将其转换为Integer类型的0,而不是抛出异常或返回null。通过分析MyBatis的源码,揭示了这种容错处理的实现细节,并建议尽量保持数据库字段类型与Java类型的一致性以避免类似问题。
摘要由CSDN通过智能技术生成

mybatis字段映射的容错性

起因从一个bug说起,大致经历如下:

经过一次selectById,然后用查出来的数据做updateById。
数据的值 由 '' --> 0;
找遍相关代码,没有发现什么地方有setType(0)的动作,然后怀疑mybatis查询时的字段映射做了容错处理,将''转换为Integer的0。
复现:造一条数据,数据库值为'',然后selectById,发现得到的type确实是0;

为了验证猜想,对跟踪了mybatis的相关源码。

mybatis在查询完成数据库后,需要进行字段映射。
mybatis字段映射的任务有:

  • 数据库属性与java属性的映射
  • 数据库类型与java类型的转换

类型的自动转换里有一些猫腻,在做类型转换的时候,如果遇到困难(类型不匹配),可以选择抛异常,也可以选择容错。而mybatis选择的是容错。容错是一中缺乏严谨性的策略。

从一个例子说起字段映射的容错性

java类型private Integer type;
mysql类型type` char(1) DEFAULT '' COMMENT '类型 (1:KA 和 2:PA)',

mybatis处理字段映射的逻辑主要是在DefaultResultSetHandlerorg.apache.ibatis.executor.resultset.DefaultResultSetHandler

public void handleRowValues(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
    if (resultMap.hasNestedResultMaps()) {
        ensureNoRowBounds();
        checkResultHandler();
        handleRowValuesForNestedResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
    } else {
        // 简单类型的映射都会进入这里
        handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
    }
}

image

image

根据不同的类型,进入不同的TypeHandler.

mybatis提供的Handler有如下几种。

image

如Integet类型就被IntegerTypeHandler

此处用的方法如下,ResultSet.getInt

@Override
  public Integer getNullableResult(ResultSet rs, String columnName)
      throws SQLException {
    int result = rs.getInt(columnName);
    return result == 0 && rs.wasNull() ? null : result;
  }

int result = rs.getInt(columnName);

image

代码跟踪到此,可发现mysql查询的结果为空字符串,也就是 '\u0000',和数据库值是一致的。

image

最后围绕在一个复杂的三目运算符

public int resultSet_getInt(ResultSetProxy rs, String columnLabel) throws SQLException {
        return this.pos < this.filterSize ? this.nextFilter().resultSet_getInt(this, rs, columnLabel) : rs.getResultSetRaw().getInt(columnLabel);
    }

最终在一个getInt的方法里找到了答案,默认赋0;

image

此处可以得到结论,mybatis的字段映射时,会有少量的容错处理,将数据库的CHAR类型的 空字符串 转换Integer做了容错,没有抛异常,也没有返回null,选择的是int的默认值0。
同理如果其它类型,也会有相关的默认值容错,如getDouble的0.0;getBigDecimal的new BigDecimal(0);...

根本性的避免此类问题的发生,还需数据库字段类型和java的类型尽量保持一致。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值