最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

淺談MyBatis Plus主鍵設(shè)置策略

 更新時(shí)間:2022年07月08日 11:37:48   作者:qinghuazs  
本文主要介紹了MyBatis Plus主鍵設(shè)置策略,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

根據(jù)一次插入失敗報(bào)錯(cuò)來(lái)了解下MyBatis Plus主鍵設(shè)置策略
今天學(xué)習(xí)使用MyBatis Plus,發(fā)現(xiàn)使用代碼生成器生成對(duì)應(yīng)的實(shí)體類(lèi)、Service和Mapper后,在保存數(shù)據(jù)時(shí)報(bào)錯(cuò)

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 more
Caused 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 more
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
Caused 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

實(shí)體類(lèi)City的主鍵是Integer類(lèi)型的,在進(jìn)行insert操作時(shí),MyBatis Plus自動(dòng)生成了一個(gè)Long類(lèi)型的主鍵id,導(dǎo)致參數(shù)類(lèi)型不匹配,出現(xiàn)上述錯(cuò)誤

經(jīng)過(guò)查看日志和調(diào)試發(fā)現(xiàn),MyBatis最終調(diào)用BeanWrapper的setBeanProperty方法,通過(guò)反射執(zhí)行最終的插入操作(增刪改查應(yīng)該都是通過(guò)此處的反射,不過(guò)暫時(shí)只調(diào)試了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即為我們想要保存到數(shù)據(jù)庫(kù)的實(shí)體信息(不帶ID信息),value為主鍵信息,此時(shí)主鍵值已經(jīng)是一個(gè)Long類(lèi)型的值,我們接著向上看value是哪里傳過(guò)來(lái)的

setBeanProperty是一個(gè)私有方法,在本類(lèi)調(diào)用,查詢(xún)看到set(PropertyTokenizer prop, Object value)方法調(diào)用了它

@Override
public 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

查看報(bào)錯(cuò)日志可以看到,BeanWrapper的上一層是MetaObject,我們找到MetaObject,看到在getValue方法中調(diào)用了BeanWrapper的set方法(BeanWrapper實(shí)現(xiàn)了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中的主鍵值也是上層調(diào)用傳入的,繼續(xù)根據(jù)錯(cuò)誤日志向上看:MybatisDefaultParameterHandler

    /**
     * <p>
     * 自定義元對(duì)象填充控制器
     * </p>
     *
     * @param metaObjectHandler 元數(shù)據(jù)填充處理器
     * @param tableInfo         數(shù)據(jù)庫(kù)表反射信息
     * @param ms                MappedStatement
     * @param parameterObject   插入數(shù)據(jù)庫(kù)對(duì)象
     * @return Object
     */
    protected static Object populateKeys(MetaObjectHandler metaObjectHandler, TableInfo tableInfo,
                                         MappedStatement ms, Object parameterObject) {
        if (null == tableInfo || StringUtils.isEmpty(tableInfo.getKeyProperty()) || null == tableInfo.getIdType()) {
            /* 不處理 */
            return parameterObject;
        }
        /* 自定義元對(duì)象填充控制器 */
        MetaObject metaObject = ms.getConfiguration().newMetaObject(parameterObject);
        if (ms.getSqlCommandType() == SqlCommandType.INSERT) {
            if (tableInfo.getIdType().getKey() >= 2) {
                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());
                    }
                }
            }
            // 插入填充
            if (metaObjectHandler.openInsertFill()) {
                metaObjectHandler.insertFill(metaObject);
            }
        } else if (ms.getSqlCommandType() == SqlCommandType.UPDATE && metaObjectHandler.openUpdateFill()) {
            // 更新填充
            metaObjectHandler.updateFill(metaObject);
        }
        return metaObject.getOriginalObject();
    }

在populateKeys方法中調(diào)用了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());
                    }
                }

可以看到,此處根據(jù)IdType生成不同類(lèi)型的主鍵id,IdType是一個(gè)枚舉類(lèi),定義了生成ID的類(lèi)型

  • AUTO 數(shù)據(jù)庫(kù)ID自增
  • INPUT 用戶(hù)輸入ID
  • ID_WORKER 全局唯一ID,Long類(lèi)型的主鍵
  • ID_WORKER_STR 字符串全局唯一ID
  • UUID 全局唯一ID,UUID類(lèi)型的主鍵
  • NONE 該類(lèi)型為未設(shè)置主鍵類(lèi)型

當(dāng)IdType的類(lèi)型為ID_WORKER、ID_WORKER_STR或者UUID時(shí),主鍵由MyBatis Plus的IdWorker類(lèi)生成

ID_WORKER

調(diào)用IdWorker的getId()方法,生成一個(gè)與時(shí)間相關(guān)的主鍵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) {
            // 相同毫秒內(nèi),序列號(hào)自增
            sequence = (sequence + 1) & sequenceMask;
            if (sequence == 0) {
                // 同一毫秒的序列數(shù)已經(jīng)達(dá)到最大
                timestamp = tilNextMillis(lastTimestamp);
            }
        } else {
            // 不同毫秒內(nèi),序列號(hào)置為 1 - 3 隨機(jī)數(shù)
            sequence = ThreadLocalRandom.current().nextLong(1, 3);
        }

        lastTimestamp = timestamp;

        return ((timestamp - twepoch) << timestampLeftShift)    // 時(shí)間戳部分
            | (datacenterId << datacenterIdShift)           // 數(shù)據(jù)中心部分
            | (workerId << workerIdShift)                   // 機(jī)器標(biāo)識(shí)部分
            | sequence;                                     // 序列號(hào)部分
    }

ID_WORKER_STR

將worker.nextId()的返回值轉(zhuǎn)化為字符串,和getId()方法相似

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

UUID

去除中劃線(xiàn)的UUID字符串

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

此時(shí),已經(jīng)基本可以確認(rèn),問(wèn)題出在IdType的配置上,那么這個(gè)IdType從哪里獲取的呢?TableInfo中獲取的!

TableInfo是數(shù)據(jù)庫(kù)表反射信息實(shí)體類(lèi),此處由其他方法傳入的,查看日志:

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

通過(guò)日志可以看出,populateKeys()方法是在processBatch()方法中調(diào)用的,找到該方法

    /**
     * <p>
     * 批量(填充主鍵 ID)
     * </p>
     *
     * @param ms
     * @param parameterObject 插入數(shù)據(jù)庫(kù)對(duì)象
     * @return
     */
    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 {
                        /*
                         * 非表映射類(lèi)不處理
                         */
                        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;
    }

下面對(duì)TableInfo生成的這段代碼做個(gè)說(shuō)明

                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:要保存到數(shù)據(jù)庫(kù)中的實(shí)體類(lèi)信息

我在保存數(shù)據(jù)時(shí),參數(shù)形式并不是Map類(lèi)型的,所以直接跳轉(zhuǎn)到else中

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

根據(jù)保存的實(shí)體類(lèi)的類(lèi)型去獲取數(shù)據(jù)庫(kù)表反射信息

我們看下getTableInfo()方法的實(shí)現(xiàn)

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

從tableInfoCache中獲取指定類(lèi)型的數(shù)據(jù)庫(kù)反射信息。tableInfoCache是一個(gè)線(xiàn)程安全的私有靜態(tài)Map,主要用于存放類(lèi)型和數(shù)據(jù)庫(kù)表的映射關(guān)系。斷點(diǎn)調(diào)試到此處,看下tableInfoCache的內(nèi)容

這里寫(xiě)圖片描述

可以看到,idType的值為ID_WORKER,即生成一個(gè)與時(shí)間相關(guān)的Long類(lèi)型的id。在放入到tableInfoCache的時(shí)候就已經(jīng)指定了idType的值。

查看TableInfoHelper的源碼可以得知,initTableInfo()方法負(fù)責(zé)initTableInfo的初始化

    public synchronized static TableInfo initTableInfo(MapperBuilderAssistant builderAssistant, Class<?> clazz) {
        //檢測(cè)是否已存在
        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 {
            // 兼容測(cè)試場(chǎng)景
            globalConfig = GlobalConfigUtils.DEFAULT;
        }
        /* 表名 */
        TableName table = clazz.getAnnotation(TableName.class);
        String tableName = clazz.getSimpleName();
        if (table != null && StringUtils.isNotEmpty(table.value())) {
            tableName = table.value();
        } else {
            // 開(kāi)啟字段下劃線(xiàn)申明
            if (globalConfig.isDbColumnUnderline()) {
                tableName = StringUtils.camelToUnderline(tableName);
            }
            // 大寫(xiě)命名判斷
            if (globalConfig.isCapitalMode()) {
                tableName = tableName.toUpperCase();
            } else {
                // 首字母小寫(xiě)
                tableName = StringUtils.firstToLowerCase(tableName);
            }
            // 存在表前綴
            if (null != globalConfig.getTablePrefix()) {
                tableName = globalConfig.getTablePrefix() + tableName;
            }
        }
        tableInfo.setTableName(tableName);

        // 開(kāi)啟了自定義 KEY 生成器
        if (null != globalConfig.getKeyGenerator()) {
            tableInfo.setKeySequence(clazz.getAnnotation(KeySequence.class));
        }

        /* 表結(jié)果集映射 */
        if (table != null && StringUtils.isNotEmpty(table.resultMap())) {
            tableInfo.setResultMap(table.resultMap());
        }
        List<TableFieldInfo> fieldList = new ArrayList<>();
        List<Field> list = getAllFields(clazz);
        // 標(biāo)記是否讀取到主鍵
        boolean isReadPK = false;
        boolean existTableId = existTableId(list);
        for (Field field : list) {
            /*
             * 主鍵ID 初始化
             */
            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;
            }

            /*
             * 字段, 使用 camelToUnderline 轉(zhuǎn)換駝峰寫(xiě)法為下劃線(xiàn)分割法, 如果已指定 TableField , 便不會(huì)執(zhí)行這里
             */
            fieldList.add(new TableFieldInfo(globalConfig, tableInfo, field));
        }

        /* 字段列表 */
        tableInfo.setFieldList(globalConfig, fieldList);
        /*
         * 未發(fā)現(xiàn)主鍵注解,提示警告信息
         */
        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是否存在

    /**
     * <p>
     * 判斷主鍵注解是否存在
     * </p>
     *
     * @param list 字段列表
     * @return
     */
    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;
    }

當(dāng)不存在主鍵注解時(shí),會(huì)調(diào)用initFieldId()方法對(duì)主鍵屬性進(jìn)行初始化

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

至此, 我們基本可以判斷是因?yàn)樵趯?shí)體類(lèi)City中id屬性沒(méi)有加@TableId注解,我們看下TableId的源碼

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface TableId {

    /**
     * <p>
     * 字段值(駝峰命名方式,該值可無(wú))
     * </p>
     */
    String value() default "";

    /**
     * <p>
     * 主鍵ID
     * </p>
     * {@link IdType}
     */
    IdType type() default IdType.NONE;

}

TableId的類(lèi)型通過(guò)type來(lái)指定,默認(rèn)是IdType.NONE(該類(lèi)型為未設(shè)置主鍵類(lèi)型),City表是通過(guò)數(shù)據(jù)庫(kù)的自增序列實(shí)現(xiàn)的,所以設(shè)置為AUTO

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

然后測(cè)試,程序正常運(yùn)行,保存數(shù)據(jù)成功。

擴(kuò)展

對(duì)于tableInfo默認(rèn)的idType值配置,可以看出用的是全局配置的idType,全局配置的值是在initTableInfo()方法中獲取的,有興趣的話(huà)可以去看看全局配置的實(shí)現(xiàn),此處暫不深入了

        GlobalConfiguration globalConfig;
        if (null != builderAssistant) {
            tableInfo.setCurrentNamespace(builderAssistant.getCurrentNamespace());
            tableInfo.setConfigMark(builderAssistant.getConfiguration());
            globalConfig = GlobalConfigUtils.getGlobalConfig(builderAssistant.getConfiguration());
        } else {
            // 兼容測(cè)試場(chǎng)景
            globalConfig = GlobalConfigUtils.DEFAULT;
        }

到此這篇關(guān)于淺談MyBatis Plus主鍵設(shè)置策略的文章就介紹到這了,更多相關(guān)MyBatis Plus主鍵設(shè)置內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • JAVA HTTP反向代理實(shí)現(xiàn)過(guò)程詳解

    JAVA HTTP反向代理實(shí)現(xiàn)過(guò)程詳解

    這篇文章主要介紹了JAVA HTTP反向代理實(shí)現(xiàn)過(guò)程詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-06-06
  • Spring依賴(lài)注入(DI)兩種方式的示例詳解

    Spring依賴(lài)注入(DI)兩種方式的示例詳解

    這篇文章主要介紹了Spring依賴(lài)注入(DI)的兩種方式:setter注入和構(gòu)造器注入。文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下
    2022-06-06
  • java生成xml格式文件的方法

    java生成xml格式文件的方法

    這篇文章主要介紹了java生成xml格式文件的方法,涉及java節(jié)點(diǎn)遍歷與屬性操作的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2016-07-07
  • java web開(kāi)發(fā)中獲取tomcat上properties文件內(nèi)容的方法

    java web開(kāi)發(fā)中獲取tomcat上properties文件內(nèi)容的方法

    java web開(kāi)發(fā)中如何獲取tomcat上properties文件內(nèi)容的方法,方便文件存儲(chǔ)位置的修改,解耦和,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-07-07
  • Jvisualvm監(jiān)控遠(yuǎn)程SpringBoot項(xiàng)目的過(guò)程詳解

    Jvisualvm監(jiān)控遠(yuǎn)程SpringBoot項(xiàng)目的過(guò)程詳解

    這篇文章主要介紹了Jvisualvm監(jiān)控遠(yuǎn)程SpringBoot項(xiàng)目,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-04-04
  • java web SpringMVC后端傳json數(shù)據(jù)到前端頁(yè)面實(shí)例代碼

    java web SpringMVC后端傳json數(shù)據(jù)到前端頁(yè)面實(shí)例代碼

    本篇文章主要介紹了java web SpringMVC后端傳json數(shù)據(jù)到前端頁(yè)面實(shí)例代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。
    2017-03-03
  • java http token請(qǐng)求代碼實(shí)例

    java http token請(qǐng)求代碼實(shí)例

    這篇文章主要介紹了java http token請(qǐng)求,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-03-03
  • Java超詳細(xì)透徹講解接口

    Java超詳細(xì)透徹講解接口

    接口是Java中最重要的概念之一,它可以被理解為一種特殊的類(lèi),不同的是接口的成員沒(méi)有執(zhí)行體,是由全局常量和公共的抽象方法所組成,本文給大家介紹Java接口,感興趣的朋友一起看看吧
    2022-05-05
  • Java使用Poi導(dǎo)出Excel表格方法實(shí)例

    Java使用Poi導(dǎo)出Excel表格方法實(shí)例

    這篇文章主要給大家介紹了關(guān)于Java使用Poi導(dǎo)出Excel表格的相關(guān)資料,Java POI是一個(gè)用于操作Microsoft Office格式的Java API庫(kù),可以使用它來(lái)導(dǎo)出Excel文件,需要的朋友可以參考下
    2023-10-10
  • 利用Spring boot如何創(chuàng)建簡(jiǎn)單的web交互應(yīng)用

    利用Spring boot如何創(chuàng)建簡(jiǎn)單的web交互應(yīng)用

    這篇文章主要介紹了利用Spring boot如何創(chuàng)建簡(jiǎn)單的web交互應(yīng)用的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家具有一定的參考價(jià)值,需要的朋友們下面來(lái)一起看看吧。
    2017-04-04

最新評(píng)論

五大连池市| 宽甸| 双城市| 灵川县| 崇文区| 宝坻区| 吴忠市| 普定县| 石嘴山市| 巴东县| 江源县| 新宾| 宜川县| 津市市| 华亭县| 遵义市| 家居| 五指山市| 蓬莱市| 弋阳县| 施甸县| 翼城县| 通许县| 白河县| 克什克腾旗| 金华市| 扶绥县| 封丘县| 呼玛县| 花垣县| 定南县| 大悟县| 吴桥县| 保亭| 攀枝花市| 水城县| 丰城市| 辉南县| 贵阳市| 东乌珠穆沁旗| 泸水县|