问题描述
Caused by: org.apache.ibatis.reflection.ReflectionException: Could not set property ‘id’ of ‘class XXX’ with value ‘XXX’ Cause: java.lang.IllegalArgumentException: argument type mismatch
这是mybatis保存数据时报的一个错,跟着源码找了一下原因。如下:
因为mybatis的全局配置com.baomidou.mybatisplus.core.config.GlobalConfig.DbConfig中,主键类型默认是ID_WORKER。
public static class DbConfig {
/**
* 主键类型(默认 ID_WORKER)
*/
private IdType idType = IdType.ID_WORKER;
在表对应的实体类加载时,主键初始化流程中com.baomidou.mybatisplus.core.metadata.TableInfoHelper#initTableIdWithoutAnnotation,如果数据库表对应的实体类中有个字段名为id,会被默认当做存在的主键,并且设置主键自动生成器为全局配置的IdType.
/**
* 默认表主键名称
*/
private static final String DEFAULT_ID_NAME = "id";
/**
* <p>
* 主键属性初始化
* </p>
*
* @param tableInfo 表信息
* @param field 字段
* @param clazz 实体类
* @return true 继续下一个属性判断,返回 continue;
*/
private static boolean initTableIdWithoutAnnotation(GlobalConfig.DbConfig dbConfig, TableInfo tableInfo,
Field field, Class<?> clazz) {
// 省略......
if (DEFAULT_ID_NAME.equalsIgnoreCase(column)) {
if (StringUtils.isEmpty(tableInfo.getKeyColumn())) {
tableInfo.setKeyRelated(checkRelated(tableInfo.isUnderCamel(), field.getName(), column))
.setIdType(dbConfig.getIdType())
.setKeyColumn(column)
.setKeyProperty(field.getName())
.setKeyType(field.getType());
return true;
} else {
throwExceptionId(clazz);
}
}
return false;
}
在调用insert类型的方法时,如果主键为空,会根据IdType的类型来填充主键,生成主键的方法是IdWorker.getId()
/**
* 自定义元对象填充控制器
*
* @param metaObjectHandler 元数据填充处理器
* @param tableInfo 数据库表反射信息
* @param ms MappedStatement
* @param parameterObject 插入数据库对象
* @return Object
*/
protected static Object populateKeys(MetaObjectHandler metaObjectHandler, TableInfo tableInfo,
MappedStatement ms, Object parameterObject, boolean isInsert) {
// 省略......
// 填充主键
if (isInsert && !StringUtils.isEmpty(tableInfo.getKeyProperty())
&& null != tableInfo.getIdType() && tableInfo.getIdType().getKey() >= 3) {
Object idValue = metaObject.getValue(tableInfo.getKeyProperty());
/* 自定义 ID */
if (StringUtils.checkValNull(idValue)) {
if (tableInfo.getIdType() == IdType.ID_WORKER) {
metaObject.setValue(tableInfo.getKeyProperty(), IdWorker.getId());
} else if (tableInfo.getIdType() == IdType.ID_WORKER_STR) {
metaObject.setValue(tableInfo.getKeyProperty(), IdWorker.getIdStr());
} else if (tableInfo.getIdType() == IdType.UUID) {
metaObject.setValue(tableInfo.getKeyProperty(), IdWorker.get32UUID());
}
}
}
// 省略......
}
IdWorker.getId()方法是通过时间戳生成的一个lang类型的随机数,此时如果我们的id类型是Integer,就会报错argument type mismatch了。