mybaits updateWrapper更新报错:无效的列类型: 1111
这是一个非常经典的 MyBatis 异常,通常发生在使用 Oracle 数据库,或者某些特定配置下的 MySQL/PostgreSQL 数据库时。
原因分析
报错信息 Error setting null for parameter #1 with JdbcType OTHER 揭示了原因:
- 你使用
UpdateWrapper的set方法设置null值。 - MyBatis 在生成 SQL 参数映射时,因为值是
null,它不知道这个参数具体的数据库字段类型(是 Long?是 String?还是 Date?)。 - MyBatis 默认将未知的 null 参数类型标记为
JdbcType.OTHER(即java.sql.Types.OTHER)。 - Oracle 数据库驱动(以及部分旧版驱动)无法处理
JdbcType.OTHER类型,它们不知道如何将这个“OTHER”类型的 null 存入数据库,从而抛出无效的列类型: 1111(1111 正是OTHER的代码)。
解决方案
这里有三种解决办法,按推荐程度排序:
方法一:全局配置(推荐,最省事)
在 application.yml 或 application.properties 中配置 MyBatis,告诉它:当遇到 null 参数且不知道类型时,统一当作 NULL (VARCHAR) 或具体的类型处理,不要用 OTHER。
对于绝大多数数据库(包括 Oracle),配置为 NULL (其实是 VARCHAR 类型) 是兼容的。
YAML 配置:
mybatis-plus:
configuration:
jdbc-type-for-null: 'NULL' # 注意这里必须加引号,NULL 是枚举值字符串
或者(如果你用的是 MyBatis 原生配置):
mybatis:
configuration:
jdbc-type-for-null: 'NULL'
解释: 加上这个配置后,MyBatis 再遇到 null 值时,会使用 java.sql.Types.NULL (本质上是 VARCHAR 处理方式) 告诉数据库“这是一个 null”,数据库就能正常接收了。
方法二:使用 setSql 方法绕过参数映射(局部解决)
如果你不想修改全局配置,或者只想在这个特定的地方解决这个问题,可以使用 UpdateWrapper 的 setSql 方法。这种方法是直接拼接 SQL 片段,而不是作为参数传入,因此不会触发 JDBC 类型判断。
修改前的代码:
updateWrapper.set(User::getA, null); // 这里会报错
修改后的代码:
// 直接写 SQL 片段 "a = null"
// 注意:如果你的数据库字段名不是驼峰转下划线,请写实际的数据库列名
updateWrapper.setSql("a = null");
// 或者配合 MyBatis-Plus 的自动映射工具类(防止硬编码字段名)
// 这里的 String "a" 需要是数据库列名
updateWrapper.setSql(StrUtil.toUnderlineCase(User::getA.getName()) + " = null");
优点: 不需要改配置,直接生成 SET a = null 的 SQL,执行效率高。
缺点: 字段名容易写死字符串,且失去了部分防 SQL 注入的预编译保护(虽然 = null 本身没风险)。
方法三:在实体类字段上指定 JdbcType(不推荐)
你可以在实体类的字段上强制指定 JdbcType,这样 MyBatis 在处理参数时就知道该用什么类型了。
@TableField(updateStrategy = FieldStrategy.IGNORED, jdbcType = JdbcType.BIGINT)
private Long a;
注意: 这种方式在 updateById 时有效,但在 UpdateWrapper.set 中传 null 值时,MyBatis-Plus 有时无法读取到这个注解配置,可能依然会报错,因此方法一通常是最稳妥的。
总结建议
直接在配置文件中加上 jdbc-type-for-null: 'NULL'。这是解决 MyBatis 处理 null 值报 invalid column type: 1111 的标准做法,能一劳永逸地解决项目中所有类似的 null 值更新问题。

浙公网安备 33010602011771号