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

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

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值