MyBatis-Plus 主键自动生成源码解析 (问题: 主键生成失效???)

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 [email protected] 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()));  //单独使用雪花算法

今天的文章就到这啦,希望能帮助到你!

猜你喜欢

转载自blog.csdn.net/AKALXH/article/details/115524808
今日推荐