Loading

MybatisPlus更新null到datetime2字段报错:不允许从数据类型 varbinary 到 datetime2 的隐式转换

背景

今日做开发,数据库使用了SQLServer,expiredTime的值为null时更新报错了,其字段类型为datetime2:

image

Caused by: com.microsoft.sqlserver.jdbc.SQLServerException: 不允许从数据类型 varbinary 到 datetime2 的隐式转换。请使用 CONVERT 函数来运行此查询。

解决方案

目前发现两种解决方案,这两种方法都是类似的。

方法一 指定mapping

不用写JdbcType.,直接写枚举的名称,比如TIMESTAMP

lambdaUpdate()
    .eq(ShortLink::getId, id)
    .set(ShortLink::getExpiredTime, req.getExpiredTime(), "jdbcType=TIMESTAMP")
    .set(ShortLink::getStatus, req.getStatus())
    .update();

方法二 在XML里写jdbcType

<update id="updateData">
    UPDATE table
    SET
        ExpiredTime = #{req.expiredTime,jdbcType=TIMESTAMP}
    WHERE Id = #{id}
</update>

还有一种方法就是把数据库的字段类型设置成datetime,这样更新就不会报错。

网上说的TableField注解里加jdbcType或者typeHandler是没用的,这两个只对查询后的结果有效。

根本原因

根本原因是在更新数据时,因为值为null,jdbcType被自动设置为了JdbcType.OTHER,同时可能因为SQLServer的datetime2没有做自动转换,导致报错。

我们都知道,执行SQL会使用PreparedStatement,然后通过set设置参数的值。

SQLServer的驱动有它自己的PreparedStatement,SQLServerPreparedStatement

在SQLServerPreparedStatement的setNull方法里打一个断点,就能看到jdbcType的值是1111,对应就是JdbcType.OTHER

public final void setNull(int index, int jdbcType) throws SQLServerException {
    if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
        loggerExternal.entering(getClassNameLogging(), "setNull", new Object[] {index, jdbcType});
    checkClosed();
    setObject(setterGetParam(index), null, JavaType.OBJECT, JDBCType.of(jdbcType), null, null, false, index, null);
    loggerExternal.exiting(getClassNameLogging(), "setNull");
}

image

那这个jdbcType又来自哪?来自DefaultParameterHandler

image

这里可以通过配置来改变jdbcTypeForNull的值,配置成TIMESTAMP是可以的,但是可能对其他字段有影响,不推荐,配置成NULL一样的问题。(如果要配置成NULL不要写成小写的null,否则真的会是null,或者外面加双引号)

mybatis-plus:
  configuration:
    jdbc-type-for-null: TIMESTAMP

上面是jdbcType和值都为null的情况,一番DEBUG后发现,jdbcType的值来自于parameterMappings

SqlSourceBuilder.ParameterMappingTokenHandler.buildParameterMapping(String content)方法。

这个方法会解析传入的content,也就是#{}中间的值,然后根据值去设置jdbcType等属性。

这里可以看到,并没有指定jdbcType。

image

如果指定了,值会是这样的:

image

有没有办法加上jdbcType呢?查看mybatis-plus的源码,发现需要传入一个叫mapping的参数。

image

默认情况下mapping会是null。

posted @ 2025-06-05 17:14  马卡龙MK  阅读(221)  评论(0)    收藏  举报