mybatis jdbcType的作用,无效的列类型错误解决办法

在使用mybatis时,我们可以指定jdbcType,对jdbcType一直有疑惑,有时候可以不加,有时候不加又会报错,网上对于jdbcType的解释也不是很全面,或者可能就是错的,今天专门研究了下,算是对这个知识点有了些了解。

首先说结论,对于如下一条insert语句(这里只是做测试,实际中肯定不会这么写),如果我们的age传的空,那么对于mysql数据库可以正常插入,对于oracle数据库,会报错“无效的列类型”。也就是说对于mysql数据库的插入来说,jdbcType是没用的,oracle数据库是有用的(值为null时有用)。

insert into test(id, name, age)
values (7, #{name,jdbcType=VARCHAR},#{age})

我没有测试更新的情况,但是我猜测结论应该是一样的。对于查询操作,在mybatis配置<resultMap>时也可以指定jdbcType,这里的jdbcType至少在我测试时也没发现有什么作用(mysql, oracle都是),当然可能只是我没发现,不代表没有作用,不作为编码建议。

insert操作时jdbcType的作用测试

这里只分析insert操作时,为什么mysql和oracle表现会不同。

我们用如下代码来进行测试。

mybatis mapper中的sql如下,因为oracle自增主键比较麻烦,这里为了方便写死了id,仅测试用。

    <insert id="testJdbcType">
        insert into t_user(id, name, age)
        values (7, #{name,jdbcType=VARCHAR}, #{age})
    </insert>

java测试代码如下,这里就不贴全部代码了,用过mybatis应该都能看懂。

    User user = new User();
    user.setName("zzj");
    user.setAge(null);
    mapper.testJdbcType(user);

然后我们分别连接mysql和oracle,查看执行结果,mysql可以正常插入,但是oracle数据库会报如下错误(Error setting null for parameter #2 with JdbcType OTHER .   java.sql.SQLException: 无效的列类型)

原因分析

mybatis中的增删改查基本都是用PreparedStatement来实现的,PreparedStatement有个setNull方法,方法签名如下:

void setNull(int parameterIndex, int sqlType) throws SQLException;

当我们要插入的值是null时,mybatis就会调用PreparedStatement的setNull来设置对应的参数。我们跟踪下mybatis执行过程,可以发现是在org.apache.ibatis.scripting.defaults.DefaultParameterHandler#setParameters这个方法中进行sql的参数设置。我们断点执行到这个方法,如下图。

从上图可以发现,由于我们age参数没有设置jdbcType,JdbcType jdbcType = parameterMapping.getJdbcType();这一行代码获取到的jdbcType为null,这时就会进入到if里,把jdbcType赋值为默认值,默认值是JdbcType.OTHER。然后接着执行第87行typeHandler.setParameter(ps, i + 1, value, jdbcType);,这一行就是对sql中的第二个参数进行设置,继续向下调试会发现,最终会调用PreparedStatement的setNull方法去设置null值,由于java.sql.PreparedStatement是个接口,具体怎么setNull,是由不同的数据库驱动程序去实现的。

我们先来看mysql的setNull方法,如下图。

可以看到,尽管第2个参数为sqlType,但是mysql实现中并没有用到这个参数,所以jdbcType的值对mysql是没有什么用的。

我们再来看oracle是如何实现setNull的,如下图,由于下载不到源码,所以oracle的代码看起来没那么直观,不过对于分析完全够用了。

 

 从上图可以看出,oracle的setNull会调用setNullCritical,而setNullCritical中又会用jdbcType这个参数调用getInternalType,这个方法内部是一长串的switch case判断,可以发现对于找不到的jdbcType,这个方法会抛出异常,这个异常就是上面我们做测试时的异常来源。而我们知道,上面mybatis把jdbcType默认设置成了JdbcType.OTHER,这个值oracle是不支持的,所以报错了。

有了上面的分析,我们就知道mybatis在插入数据时是怎么使用jdbcType的了,由此也可得出结论,对于插入操作,如果某个字段值为null,jdbcType的设置对mysql数据库没什么用,对oracle数据库有用。

MyBatis-Plus中,当传递的查询参数为null时,可能会引发无效列类型错误代码1111。这个错误通常在解析参数类型时出现问题。如果参数是Map类型或Java Object类型,并且属性的类型不一致,例如某些属性是String类型,而其他属性是Integer类型,那么MyBatis在解析时可能无法正确识别类型,从而导致错误。为了解决这个问题,可以在MyBatis的参数解析过程中进行特殊处理。可以通过加入如下代码进行特殊判断处理: ```xml <if test="fieldValue == null"> #{fieldValue, jdbcType = VARCHAR} </if> <if test="fieldValue != null"> #{fieldValue} </if> ``` 这样,当传入的参数值为null时,会将其转换为VARCHAR类型。这样就可以避免无效列类型错误。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [Oracle 结合Mybatis-plus 查询报错:无效列类型: 1111](https://blog.csdn.net/qq_24006731/article/details/88538810)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [Mybatis - 无效列类型: 1111](https://blog.csdn.net/Dream_Weave/article/details/124496550)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值