MyBatis-Plus 主键自动生成源码解析 (及问题主键生成失效?) |
原因:
今天测试一条增加功能时,给我报了个错误:(如下)
### Error updating database. Cause: java.sql.SQLIntegrityConstraintViolationException: Column 'id' cannot be null
很普通的一个问题 , 数据库的id字段是主键不为null的,插入时为空.约束限制导致这个异常抛出.
思路:
1.首先检查了该有的注解加上没:
@TableName("数据库表名")
public class 类名 implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 自增记录
*/
@TableId(value = "id", type = IdType.ASSIGN_ID)
@JsonSerialize(using = ToStringSerializer.class)
private Long id; //可以为 String 或者 Long
2.然后检查数据库对应字段匹配没, ASSIGN_ID是雪花算法生成的位数比较大,需要用 bigint 来存储. (检查完也没毛病)
3.然后查看了yml配置:
mybatis-plus:
global-config:
db-config:
id-type: ASSIGN_UUID #也可以用3表示
也没问题,因为之前代码加上了这段配置也无影响,可能是代码的优先级要高于配置吧(我的猜测.)
这就很脑壳疼了,都没问题啊.怎么就为空呢? 后来清除编译文件重新编译,然后试了下其他主键生成策略都没问题,就唯独ASSIGN_ID 不行 , 突然感觉被针对了. 一系列操作下来还是没用. 百度无果(没有类似的问题).
于是只好跟踪源码看到底是个什么情况.
1.找到属性打好断点,于是跟着就来到了 MybatisDefaultParameterHandler 类 ,用来处理默认参数赋值的.
里面有很多的方法,但是我需要找的方法就是它:
/**
* 填充主键
*
* @param tableInfo 数据库表反射信息
* @param metaObject 元数据对象
* @param entity 实体信息
*/
protected static void populateKeys(TableInfo tableInfo, MetaObject metaObject, Object entity) {
final IdType idType = tableInfo.getIdType();
final String keyProperty = tableInfo.getKeyProperty();
if (StringUtils.isNotBlank(keyProperty) && null != idType && idType.getKey() >= 3) {
final IdentifierGenerator identifierGenerator = GlobalConfigUtils.getGlobalConfig(tableInfo.getConfiguration()).getIdentifierGenerator();
Object idValue = metaObject.getValue(keyProperty);
if (StringUtils.checkValNull(idValue)) {
if (idType.getKey() == IdType.ASSIGN_ID.getKey()) {
if (Number.class.isAssignableFrom(tableInfo.getKeyType())) {
metaObject.setValue(keyProperty, identifierGenerator.nextId(entity)); //这个方法生成ID然后赋值
} else {
metaObject.setValue(keyProperty, identifierGenerator.nextId(entity).toString());
}
} else if (idType.getKey() == IdType.ASSIGN_UUID.getKey()) {
metaObject.setValue(keyProperty, identifierGenerator.nextUUID(entity));
}
}
}
}
看源码可以知道生成id的方法:
identifierGenerator.nextId(entity)
于是进入方法查看:
/**
* Id生成器接口
*
* @author sd-wangtaicheng@sdcncsi.com.cn nieqiuqiu
* @since 2019-10-15
* @since 3.3.0
*/
public interface IdentifierGenerator {
/**
* 生成Id
*
* @param entity 实体
* @return id
*/
Number nextId(Object entity);
/**
* 生成uuid
*
* @param entity 实体
* @return uuid
*/
default String nextUUID(Object entity) {
return IdWorker.get32UUID();
}
到这越来越接近真相了(激动…)
继续查看 nextId() 的实现类.
@Slf4j
@Component
public class CustomIdGenerator implements IdentifierGenerator {
@Override
public Number nextId(Object entity) {
return null;
}
/**
* String 类型id生成
*
* @param entity
* @return
*/
@Override
public String nextUUID(Object entity) {
return IDGenerate.randomUUID();
}
}
到这我一脸疑惑(懵B)???
啥情况,配置类重写了这个方法,一直返回Null. 不知道这谁写的配置类,属实坑到我了.
IdentifierGenerator identifierGenerator=new DefaultIdentifierGenerator();
System.out.println(identifierGenerator.nextId(new Object())); //单独使用雪花算法
今天的文章就到这啦,希望能帮助到你!