iis服务器助手广告广告
返回顶部
首页 > 资讯 > 精选 >MyBatis Plus主键设置策略是什么
  • 250
分享到

MyBatis Plus主键设置策略是什么

2023-07-02 16:07:22 250人浏览 八月长安
摘要

这篇文章主要介绍了mybatis Plus主键设置策略是什么的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇MyBatis Plus主键设置策略是什么文章都会有所收获,下面我们一起来看看吧。根

这篇文章主要介绍了mybatis Plus主键设置策略是什么的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇MyBatis Plus主键设置策略是什么文章都会有所收获,下面我们一起来看看吧。

根据一次插入失败报错来了解下MyBatis Plus主键设置策略
今天学习使用MyBatis Plus,发现使用代码生成器生成对应的实体类、Service和Mapper后,在保存数据时报错

com.baomidou.mybatisplus.exceptions.MybatisPlusException: java.lang.reflect.InvocationTargetException    at com.baomidou.mybatisplus.MybatissqlSessionTemplate$SqlSessionInterceptor.invoke(MybatisSqlSessionTemplate.java:405)    at com.sun.proxy.$Proxy70.insert(Unknown Source)    at com.baomidou.mybatisplus.MybatisSqlSessionTemplate.insert(MybatisSqlSessionTemplate.java:243)    at com.baomidou.mybatisplus.activerecord.Model.insert(Model.java:56)    at com.lemon.rabbit.common.base.city.CityInitial.printInfo(CityInitial.java:112)    at com.lemon.rabbit.common.base.city.CityInitial.parseNextLevel(CityInitial.java:87)    at com.lemon.rabbit.common.base.city.CityInitial.test(CityInitial.java:59)    at com.lemon.rabbit.RabbitApplicationTests.contextLoads(RabbitApplicationTests.java:19)    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)    at java.lang.reflect.Method.invoke(Method.java:498)    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)    at org.springframework.test.context.junit4.statements.RunBeforeTestExecutionCallbacks.evaluate(RunBeforeTestExecutionCallbacks.java:73)    at org.springframework.test.context.junit4.statements.RunAfterTestExecutionCallbacks.evaluate(RunAfterTestExecutionCallbacks.java:83)    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:251)    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)    at com.intellij.junit4.JUnit4ideaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)    at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)Caused by: java.lang.reflect.InvocationTargetException    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)    at java.lang.reflect.Method.invoke(Method.java:498)    at com.baomidou.mybatisplus.MybatisSqlSessionTemplate$SqlSessionInterceptor.invoke(MybatisSqlSessionTemplate.java:401)    ... 37 moreCaused by: org.apache.ibatis.exceptions.PersistenceException: ### Error updating database.  Cause: org.apache.ibatis.reflection.ReflectionException: Could not set property 'id' of 'class com.lemon.rabbit.model.City' with value '1017367047558582273' Cause: java.lang.IllegalArgumentException: argument type mismatch### Cause: org.apache.ibatis.reflection.ReflectionException: Could not set property 'id' of 'class com.lemon.rabbit.model.City' with value '1017367047558582273' Cause: java.lang.IllegalArgumentException: argument type mismatch    at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:30)    at org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:200)    at org.apache.ibatis.session.defaults.DefaultSqlSession.insert(DefaultSqlSession.java:185)    ... 42 moreCaused by: org.apache.ibatis.reflection.ReflectionException: Could not set property 'id' of 'class com.lemon.rabbit.model.City' with value '1017367047558582273' Cause: java.lang.IllegalArgumentException: argument type mismatch    at org.apache.ibatis.reflection.wrapper.BeanWrapper.setBeanProperty(BeanWrapper.java:185)    at org.apache.ibatis.reflection.wrapper.BeanWrapper.set(BeanWrapper.java:59)    at org.apache.ibatis.reflection.MetaObject.setValue(MetaObject.java:140)    at com.baomidou.mybatisplus.MybatisDefaultParameterHandler.populateKeys(MybatisDefaultParameterHandler.java:217)    at com.baomidou.mybatisplus.MybatisDefaultParameterHandler.processBatch(MybatisDefaultParameterHandler.java:156)    at com.baomidou.mybatisplus.MybatisDefaultParameterHandler.<init>(MybatisDefaultParameterHandler.java:71)    at com.baomidou.mybatisplus.MybatisXMLLanguageDriver.createParameterHandler(MybatisXMLLanguageDriver.java:37)    at org.apache.ibatis.session.Configuration.newParameterHandler(Configuration.java:545)    at org.apache.ibatis.executor.statement.BaseStatementHandler.<init>(BaseStatementHandler.java:69)    at org.apache.ibatis.executor.statement.PreparedStatementHandler.<init>(PreparedStatementHandler.java:40)    at org.apache.ibatis.executor.statement.RoutingStatementHandler.<init>(RoutingStatementHandler.java:46)    at org.apache.ibatis.session.Configuration.newStatementHandler(Configuration.java:558)    at org.apache.ibatis.executor.SimpleExecutor.doUpdate(SimpleExecutor.java:48)    at org.apache.ibatis.executor.BaseExecutor.update(BaseExecutor.java:117)    at org.apache.ibatis.executor.CachingExecutor.update(CachingExecutor.java:76)    at org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:198)    ... 43 moreCaused by: java.lang.IllegalArgumentException: argument type mismatch    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)    at java.lang.reflect.Method.invoke(Method.java:498)    at org.apache.ibatis.reflection.invoker.MethodInvoker.invoke(MethodInvoker.java:41)    at org.apache.ibatis.reflection.wrapper.BeanWrapper.setBeanProperty(BeanWrapper.java:180)    ... 58 more

实体类City的主键是Integer类型的,在进行insert操作时,MyBatis Plus自动生成了一个Long类型的主键id,导致参数类型不匹配,出现上述错误

经过查看日志和调试发现,MyBatis最终调用BeanWrapper的setBeanProperty方法,通过反射执行最终的插入操作(增删改查应该都是通过此处的反射,不过暂时只调试了insert方法)

private void setBeanProperty(PropertyTokenizer prop, Object object, Object value) {    try {        Invoker method = metaClass.getSetInvoker(prop.getName());        Object[] params = {value};        try {            method.invoke(object, params);        } catch (Throwable t) {            throw ExceptionUtil.unwrapThrowable(t);        }    } catch (Throwable t) {        throw new ReflectionException("Could not set property '" + prop.getName() + "' of '" + object.getClass() + "' with value '" + value + "' Cause: " + t.toString(), t);    }}

此处传入的object即为我们想要保存到数据库的实体信息(不带ID信息),value为主键信息,此时主键值已经是一个Long类型的值,我们接着向上看value是哪里传过来的

setBeanProperty是一个私有方法,在本类调用,查询看到set(PropertyTokenizer prop, Object value)方法调用了它

@Overridepublic void set(PropertyTokenizer prop, Object value) {    if (prop.getIndex() != null) {        Object collection = resolveCollection(prop, object);        setCollectionValue(prop, collection, value);    } else {      setBeanProperty(prop, object, value);    }}

set方法中的value也是其他地方传入的

Caused by: org.apache.ibatis.reflection.ReflectionException: Could not set property 'id' of 'class com.lemon.rabbit.model.City' with value '1017367047558582273' Cause: java.lang.IllegalArgumentException: argument type mismatch    at org.apache.ibatis.reflection.wrapper.BeanWrapper.setBeanProperty(BeanWrapper.java:185)    at org.apache.ibatis.reflection.wrapper.BeanWrapper.set(BeanWrapper.java:59)    at org.apache.ibatis.reflection.MetaObject.setValue(MetaObject.java:140)    at com.baomidou.mybatisplus.MybatisDefaultParameterHandler.populateKeys(MybatisDefaultParameterHandler.java:217)    at com.baomidou.mybatisplus.MybatisDefaultParameterHandler.processBatch(MybatisDefaultParameterHandler.java:156)    at com.baomidou.mybatisplus.MybatisDefaultParameterHandler.<init>(MybatisDefaultParameterHandler.java:71)    at com.baomidou.mybatisplus.MybatisXMLLanguageDriver.createParameterHandler(MybatisXMLLanguageDriver.java:37)    at org.apache.ibatis.session.Configuration.newParameterHandler(Configuration.java:545)    at org.apache.ibatis.executor.statement.BaseStatementHandler.<init>(BaseStatementHandler.java:69)    at org.apache.ibatis.executor.statement.PreparedStatementHandler.<init>(PreparedStatementHandler.java:40)    at org.apache.ibatis.executor.statement.RoutingStatementHandler.<init>(RoutingStatementHandler.java:46)    at org.apache.ibatis.session.Configuration.newStatementHandler(Configuration.java:558)    at org.apache.ibatis.executor.SimpleExecutor.doUpdate(SimpleExecutor.java:48)    at org.apache.ibatis.executor.BaseExecutor.update(BaseExecutor.java:117)    at org.apache.ibatis.executor.CachingExecutor.update(CachingExecutor.java:76)    at org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:198)    ... 43 more

查看报错日志可以看到,BeanWrapper的上一层是MetaObject,我们找到MetaObject,看到在getValue方法中调用了BeanWrapper的set方法(BeanWrapper实现了ObjectWrapper)

public void setValue(String name, Object value) {    PropertyTokenizer prop = new PropertyTokenizer(name);    if (prop.hasNext()) {        MetaObject metaValue = metaObjectForProperty(prop.getIndexedName());        if (metaValue == SystemMetaObject.NULL_META_OBJECT) {            if (value == null && prop.getChildren() != null) {                // don't instantiate child path if value is null                return;            } else {                metaValue = objectWrapper.instantiatePropertyValue(name, prop, objectFactory);            }        }        metaValue.setValue(prop.getChildren(), value);    } else {        objectWrapper.set(prop, value);    }}

MetaObject中的主键值也是上层调用传入的,继续根据错误日志向上看:MybatisDefaultParameterHandler

        protected static Object populateKeys(MetaObjectHandler metaObjectHandler, TableInfo tableInfo,                                         MappedStatement ms, Object parameterObject) {        if (null == tableInfo || StringUtils.isEmpty(tableInfo.geTKEyProperty()) || null == tableInfo.getIdType()) {                        return parameterObject;        }                MetaObject metaObject = ms.getConfiguration().newMetaObject(parameterObject);        if (ms.getSqlCommandType() == SqlCommandType.INSERT) {            if (tableInfo.getIdType().getKey() >= 2) {                Object idValue = metaObject.getValue(tableInfo.getKeyProperty());                                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());                    }                }            }            // 插入填充            if (metaObjectHandler.openInsertFill()) {                metaObjectHandler.insertFill(metaObject);            }        } else if (ms.getSqlCommandType() == SqlCommandType.UPDATE && metaObjectHandler.openUpdateFill()) {            // 更新填充            metaObjectHandler.updateFill(metaObject);        }        return metaObject.getOriginalObject();    }

在populateKeys方法中调用了metaObject.setValue()

                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());                    }                }

可以看到,此处根据IdType生成不同类型的主键id,IdType是一个枚举类,定义了生成ID的类型

  • AUTO 数据库ID自增

  • INPUT 用户输入ID

  • ID_WORKER 全局唯一ID,Long类型的主键

  • ID_WORKER_STR 字符串全局唯一ID

  • UUID 全局唯一ID,UUID类型的主键

  • NONE 该类型为未设置主键类型

当IdType的类型为ID_WORKER、ID_WORKER_STR或者UUID时,主键由MyBatis Plus的IdWorker类生成

ID_WORKER

调用IdWorker的getId()方法,生成一个与时间相关的主键id

    public static long getId() {        return worker.nextId();    }

IdWorker的getId()方法引用了Sequence的nextId()方法

    public synchronized long nextId() {        long timestamp = timeGen();        if (timestamp < lastTimestamp) {//闰秒            long offset = lastTimestamp - timestamp;            if (offset <= 5) {                try {                    wait(offset << 1);                    timestamp = timeGen();                    if (timestamp < lastTimestamp) {                        throw new RuntimeException(String.fORMat("Clock moved backwards.  Refusing to generate id for %d milliseconds", offset));                    }                } catch (Exception e) {                    throw new RuntimeException(e);                }            } else {                throw new RuntimeException(String.format("Clock moved backwards.  Refusing to generate id for %d milliseconds", offset));            }        }        if (lastTimestamp == timestamp) {            // 相同毫秒内,序列号自增            sequence = (sequence + 1) & sequenceMask;            if (sequence == 0) {                // 同一毫秒的序列数已经达到最大                timestamp = tilNextMillis(lastTimestamp);            }        } else {            // 不同毫秒内,序列号置为 1 - 3 随机数            sequence = ThreadLocalRandom.current().nextLong(1, 3);        }        lastTimestamp = timestamp;        return ((timestamp - twepoch) << timestampLeftShift)    // 时间戳部分            | (datacenterId << datacenterIdShift)           // 数据中心部分            | (workerId << workerIdShift)                   // 机器标识部分            | sequence;                                     // 序列号部分    }

ID_WORKER_STR

将worker.nextId()的返回值转化为字符串,和getId()方法相似

    public static String getIdStr() {        return String.valueOf(worker.nextId());    }

UUID

去除中划线的UUID字符串

    public static synchronized String get32UUID() {        return UUID.randomUUID().toString().replace("-", "");    }

此时,已经基本可以确认,问题出在IdType的配置上,那么这个IdType从哪里获取的呢?TableInfo中获取的!

TableInfo是数据库表反射信息实体类,此处由其他方法传入的,查看日志:

at com.baomidou.mybatisplus.MybatisDefaultParameterHandler.populateKeys(MybatisDefaultParameterHandler.java:217)at com.baomidou.mybatisplus.MybatisDefaultParameterHandler.processBatch(MybatisDefaultParameterHandler.java:156)

通过日志可以看出,populateKeys()方法是在processBatch()方法中调用的,找到该方法

        protected static Object processBatch(MappedStatement ms, Object parameterObject) {        //检查parameterObject        if (null == parameterObject) {            return null;        }        boolean isFill = false;        // 全局配置是否配置填充器        MetaObjectHandler metaObjectHandler = GlobalConfigUtils.getMetaObjectHandler(ms.getConfiguration());                if (ms.getSqlCommandType() == SqlCommandType.INSERT) {            isFill = true;        } else if (ms.getSqlCommandType() == SqlCommandType.UPDATE            && metaObjectHandler.openUpdateFill()) {            isFill = true;        }        if (isFill) {            Collection<Object> parameters = getParameters(parameterObject);            if (null != parameters) {                List<Object> objList = new ArrayList<>();                for (Object parameter : parameters) {                    TableInfo tableInfo = TableInfoHelper.getTableInfo(parameter.getClass());                    if (null != tableInfo) {                        objList.add(populateKeys(metaObjectHandler, tableInfo, ms, parameter));                    } else {                                                objList.add(parameter);                    }                }                return objList;            } else {                TableInfo tableInfo = null;                if (parameterObject instanceof Map) {                    Map map = (Map) parameterObject;                    if (map.containsKey("et")) {                        Object et = map.get("et");                        if (et != null) {                            if (et instanceof Map) {                                Map realEtMap = (Map) et;                                if (realEtMap.containsKey("MP_OPTLOCK_ET_ORIGINAL")) {//refer to OptimisticLockerInterceptor.MP_OPTLOCK_ET_ORIGINAL                                    tableInfo = TableInfoHelper.getTableInfo(realEtMap.get("MP_OPTLOCK_ET_ORIGINAL").getClass());                                }                            } else {                                tableInfo = TableInfoHelper.getTableInfo(et.getClass());                            }                        }                    }                } else {                    tableInfo = TableInfoHelper.getTableInfo(parameterObject.getClass());                }                return populateKeys(metaObjectHandler, tableInfo, ms, parameterObject);            }        }        return parameterObject;    }

下面对TableInfo生成的这段代码做个说明

                TableInfo tableInfo = null;                if (parameterObject instanceof Map) {                    Map map = (Map) parameterObject;                    if (map.containsKey("et")) {                        Object et = map.get("et");                        if (et != null) {                            if (et instanceof Map) {                                Map realEtMap = (Map) et;                                if (realEtMap.containsKey("MP_OPTLOCK_ET_ORIGINAL")) {//refer to OptimisticLockerInterceptor.MP_OPTLOCK_ET_ORIGINAL                                    tableInfo = TableInfoHelper.getTableInfo(realEtMap.get("MP_OPTLOCK_ET_ORIGINAL").getClass());                                }                            } else {                                tableInfo = TableInfoHelper.getTableInfo(et.getClass());                            }                        }                    }                } else {                    tableInfo = TableInfoHelper.getTableInfo(parameterObject.getClass());                }

parameterObject:要保存到数据库中的实体类信息

我在保存数据时,参数形式并不是Map类型的,所以直接跳转到else中

tableInfo = TableInfoHelper.getTableInfo(parameterObject.getClass());

根据保存的实体类的类型去获取数据库表反射信息

我们看下getTableInfo()方法的实现

    public static TableInfo getTableInfo(Class<?> clazz) {        return tableInfoCache.get(ClassUtils.getUserClass(clazz).getName());    }

从tableInfoCache中获取指定类型的数据库反射信息。tableInfoCache是一个线程安全的私有静态Map,主要用于存放类型和数据库表的映射关系。断点调试到此处,看下tableInfoCache的内容

MyBatis Plus主键设置策略是什么

可以看到,idType的值为ID_WORKER,即生成一个与时间相关的Long类型的id。在放入到tableInfoCache的时候就已经指定了idType的值。

查看TableInfoHelper的源码可以得知,initTableInfo()方法负责initTableInfo的初始化

    public synchronized static TableInfo initTableInfo(MapperBuilderAssistant builderAssistant, Class<?> clazz) {        //检测是否已存在        TableInfo tableInfo = tableInfoCache.get(clazz.getName());        if (StringUtils.checkValNotNull(tableInfo)) {            if (StringUtils.checkValNotNull(builderAssistant)) {                tableInfo.setConfigMark(builderAssistant.getConfiguration());            }            return tableInfo;        }        tableInfo = new TableInfo();        GlobalConfiguration globalConfig;        if (null != builderAssistant) {            tableInfo.setCurrentNamespace(builderAssistant.getCurrentNamespace());            tableInfo.setConfigMark(builderAssistant.getConfiguration());            //获取全局配置,其中包括了idType            globalConfig = GlobalConfigUtils.getGlobalConfig(builderAssistant.getConfiguration());        } else {            // 兼容测试场景            globalConfig = GlobalConfigUtils.DEFAULT;        }                TableName table = clazz.getAnnotation(TableName.class);        String tableName = clazz.getSimpleName();        if (table != null && StringUtils.isNotEmpty(table.value())) {            tableName = table.value();        } else {            // 开启字段下划线申明            if (globalConfig.isDbColumnUnderline()) {                tableName = StringUtils.camelToUnderline(tableName);            }            // 大写命名判断            if (globalConfig.isCapitalMode()) {                tableName = tableName.toUpperCase();            } else {                // 首字母小写                tableName = StringUtils.firstToLowerCase(tableName);            }            // 存在表前缀            if (null != globalConfig.getTablePrefix()) {                tableName = globalConfig.getTablePrefix() + tableName;            }        }        tableInfo.setTableName(tableName);        // 开启了自定义 KEY 生成器        if (null != globalConfig.getKeyGenerator()) {            tableInfo.setKeySequence(clazz.getAnnotation(KeySequence.class));        }                if (table != null && StringUtils.isNotEmpty(table.resultMap())) {            tableInfo.setResultMap(table.resultMap());        }        List<TableFieldInfo> fieldList = new ArrayList<>();        List<Field> list = getAllFields(clazz);        // 标记是否读取到主键        boolean isReadPK = false;        boolean existTableId = existTableId(list);        for (Field field : list) {                        if (!isReadPK) {                if (existTableId) {                    isReadPK = initTableId(globalConfig, tableInfo, field, clazz);                } else {                    isReadPK = initFieldId(globalConfig, tableInfo, field, clazz);                }                if (isReadPK) {                    continue;                }            }                        if (initTableField(globalConfig, tableInfo, fieldList, field, clazz)) {                continue;            }                        fieldList.add(new TableFieldInfo(globalConfig, tableInfo, field));        }                tableInfo.setFieldList(globalConfig, fieldList);                if (StringUtils.isEmpty(tableInfo.getKeyColumn())) {            logger.warn(String.format("Warn: Could not find @TableId in Class: %s.", clazz.getName()));        }                tableInfoCache.put(clazz.getName(), tableInfo);        return tableInfo;    }

在existTableId方法中判断主键注解@TableId是否存在

        public static boolean existTableId(List<Field> list) {        boolean exist = false;        for (Field field : list) {            TableId tableId = field.getAnnotation(TableId.class);            if (tableId != null) {                exist = true;                break;            }        }        return exist;    }

当不存在主键注解时,会调用initFieldId()方法对主键属性进行初始化

    private static boolean initFieldId(GlobalConfiguration globalConfig, TableInfo tableInfo, Field field, Class<?> clazz) {        String column = field.getName();        if (globalConfig.isCapitalMode()) {            column = column.toUpperCase();        }        if (DEFAULT_ID_NAME.equalsIgnoreCase(column)) {            if (StringUtils.isEmpty(tableInfo.getKeyColumn())) {                tableInfo.setIdType(globalConfig.getIdType());                tableInfo.setKeyColumn(column);                tableInfo.setKeyProperty(field.getName());                return true;            } else {                throwExceptionId(clazz);            }        }        return false;    }

至此, 我们基本可以判断是因为在实体类City中id属性没有加@TableId注解,我们看下TableId的源码

@Documented@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.FIELD)public @interface TableId {        String value() default "";        IdType type() default IdType.NONE;}

TableId的类型通过type来指定,默认是IdType.NONE(该类型为未设置主键类型),City表是通过数据库的自增序列实现的,所以设置为AUTO

@TableId(type = IdType.AUTO) private Integer id;

然后测试,程序正常运行,保存数据成功。

扩展

对于tableInfo默认的idType值配置,可以看出用的是全局配置的idType,全局配置的值是在initTableInfo()方法中获取的,有兴趣的话可以去看看全局配置的实现,此处暂不深入了

        GlobalConfiguration globalConfig;        if (null != builderAssistant) {            tableInfo.setCurrentNamespace(builderAssistant.getCurrentNamespace());            tableInfo.setConfigMark(builderAssistant.getConfiguration());            globalConfig = GlobalConfigUtils.getGlobalConfig(builderAssistant.getConfiguration());        } else {            // 兼容测试场景            globalConfig = GlobalConfigUtils.DEFAULT;        }

关于“MyBatis Plus主键设置策略是什么”这篇文章的内容就介绍到这里,感谢各位的阅读!相信大家对“MyBatis Plus主键设置策略是什么”知识都有一定的了解,大家如果还想学习更多知识,欢迎关注编程网精选频道。

--结束END--

本文标题: MyBatis Plus主键设置策略是什么

本文链接: https://www.lsjlt.com/news/342974.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作