001/** 002 * Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com). 003 * <p> 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * <p> 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * <p> 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package com.mybatisflex.core.keygen; 017 018import com.mybatisflex.core.FlexConsts; 019import com.mybatisflex.core.FlexGlobalConfig; 020import com.mybatisflex.annotation.KeyType; 021import com.mybatisflex.core.exception.FlexExceptions; 022import com.mybatisflex.core.table.IdInfo; 023import com.mybatisflex.core.table.TableInfo; 024import com.mybatisflex.core.util.StringUtil; 025import org.apache.ibatis.executor.keygen.Jdbc3KeyGenerator; 026import org.apache.ibatis.executor.keygen.KeyGenerator; 027import org.apache.ibatis.executor.keygen.NoKeyGenerator; 028import org.apache.ibatis.executor.keygen.SelectKeyGenerator; 029import org.apache.ibatis.mapping.*; 030import org.apache.ibatis.session.Configuration; 031 032import java.util.ArrayList; 033import java.util.Arrays; 034import java.util.List; 035 036public class MybatisKeyGeneratorUtil { 037 038 039 public static KeyGenerator createTableKeyGenerator(TableInfo tableInfo, MappedStatement ms) { 040 List<IdInfo> primaryKeyList = tableInfo.getPrimaryKeyList(); 041 042 //无主键 043 if (primaryKeyList == null || primaryKeyList.isEmpty()) { 044 return NoKeyGenerator.INSTANCE; 045 } 046 047 //多主键的 048 if (primaryKeyList.size() > 1) { 049 return new MultiPrimaryKeyGenerator(ms, tableInfo, primaryKeyList); 050 } 051 052 return createIdKeyGenerator(tableInfo, ms, primaryKeyList.get(0)); 053 } 054 055 056 public static KeyGenerator createIdKeyGenerator(TableInfo tableInfo, MappedStatement ms, IdInfo idInfo) { 057 FlexGlobalConfig.KeyConfig globalKeyConfig = FlexGlobalConfig.getConfig(ms.getConfiguration()).getKeyConfig(); 058 KeyType keyType = getKeyType(idInfo, globalKeyConfig); 059 060 if (keyType == KeyType.None) { 061 return NoKeyGenerator.INSTANCE; 062 } 063 064 //自增主键 065 if (keyType == KeyType.Auto) { 066 return Jdbc3KeyGenerator.INSTANCE; 067 } 068 069 //通过 java 生成的主键 070 if (keyType == KeyType.Generator) { 071 return new CustomKeyGenerator(ms.getConfiguration(), tableInfo, idInfo); 072 } 073 074 //通过序列生成的注解 075 String sequence = getKeyValue(idInfo, globalKeyConfig); 076 if (StringUtil.isBlank(sequence)) { 077 throw FlexExceptions.wrap("please config @Id(value=\"...\") for field: %s in class: %s" 078 , idInfo.getProperty() 079 , tableInfo.getEntityClass().getName()); 080 } 081 082 083 String selectId = ms.getId() + SelectKeyGenerator.SELECT_KEY_SUFFIX; 084 SqlSource sqlSource = ms.getLang().createSqlSource(ms.getConfiguration(), sequence.trim(), idInfo.getPropertyType()); 085 MappedStatement.Builder msBuilder = new MappedStatement.Builder(ms.getConfiguration(), selectId, sqlSource, SqlCommandType.SELECT) 086 .resource(ms.getResource()) 087 .fetchSize(null) 088 .timeout(null) 089 .statementType(StatementType.PREPARED) 090 .keyGenerator(NoKeyGenerator.INSTANCE) 091 .keyProperty(FlexConsts.ENTITY + "." + idInfo.getProperty()) 092 .keyColumn(idInfo.getColumn()) 093 .databaseId(ms.getDatabaseId()) 094 .lang(ms.getLang()) 095 .resultOrdered(false) 096 .resultSets(null) 097 .resultMaps(createIdResultMaps(ms.getConfiguration(), selectId + "-Inline", idInfo.getPropertyType(), new ArrayList<>())) 098 .resultSetType(null) 099 .flushCacheRequired(false) 100 .useCache(false) 101 .cache(ms.getCache()); 102 103 MappedStatement keyMappedStatement = msBuilder.build(); 104 ms.getConfiguration().addMappedStatement(keyMappedStatement); 105 106 //看到有的框架把 keyGenerator 添加到 mybatis 的当前配置里去,其实是完全没必要的 107 //因为只有在 xml 解析的时候,才可能存在多一个 MappedStatement 拥有同一个 keyGenerator 的情况 108 //当前每个方法都拥有一个自己的 keyGenerator 了,没必要添加 109 //this.addKeyGenerator(selectId, keyGenerator); 110 return new SelectKeyGenerator(keyMappedStatement, isKeyBefore(idInfo, globalKeyConfig)); 111 } 112 113 114 private static List<ResultMap> createIdResultMaps(Configuration configuration, 115 String statementId, Class<?> resultType, List<ResultMapping> resultMappings) { 116 ResultMap resultMap = new ResultMap.Builder(configuration, statementId, resultType, resultMappings, null) 117 .build(); 118 return Arrays.asList(resultMap); 119 } 120 121 122 /** 123 * 获取主键的 keyType,优先通过 @id 获取,获取不到通过全局配置获取 124 */ 125 public static KeyType getKeyType(IdInfo idInfo, FlexGlobalConfig.KeyConfig globalKeyConfig) { 126 KeyType keyType = idInfo.getKeyType(); 127 if (keyType != KeyType.None) { 128 return keyType; 129 } 130 131 if (globalKeyConfig != null) { 132 return globalKeyConfig.getKeyType(); 133 } 134 135 return keyType; 136 } 137 138 139 public static String getKeyValue(IdInfo idInfo, FlexGlobalConfig.KeyConfig globalKeyConfig) { 140 String value = idInfo.getValue(); 141 if (StringUtil.isBlank(value) && globalKeyConfig != null) { 142 value = globalKeyConfig.getValue(); 143 } 144 return value; 145 } 146 147 148 public static boolean isKeyBefore(IdInfo idInfo, FlexGlobalConfig.KeyConfig globalKeyConfig) { 149 Boolean before = idInfo.getBefore(); 150 if (before == null && globalKeyConfig != null) { 151 return globalKeyConfig.isBefore(); 152 } else { 153 return before == null || before; 154 } 155 } 156 157}