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.annotation.KeyType; 019import com.mybatisflex.core.FlexConsts; 020import com.mybatisflex.core.FlexGlobalConfig; 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 private MybatisKeyGeneratorUtil() { 039 } 040 041 public static KeyGenerator createTableKeyGenerator(TableInfo tableInfo, MappedStatement ms) { 042 List<IdInfo> primaryKeyList = tableInfo.getPrimaryKeyList(); 043 044 //无主键 045 if (primaryKeyList == null || primaryKeyList.isEmpty()) { 046 return NoKeyGenerator.INSTANCE; 047 } 048 049 //多主键的 050 if (primaryKeyList.size() > 1) { 051 return new MultiPrimaryKeyGenerator(ms, tableInfo, primaryKeyList); 052 } 053 054 return createIdKeyGenerator(tableInfo, ms, primaryKeyList.get(0)); 055 } 056 057 058 public static KeyGenerator createIdKeyGenerator(TableInfo tableInfo, MappedStatement ms, IdInfo idInfo) { 059 FlexGlobalConfig flexGlobalConfig = FlexGlobalConfig.getConfig(ms.getConfiguration()); 060 061 if(flexGlobalConfig == null){ 062 return NoKeyGenerator.INSTANCE; 063 } 064 065 FlexGlobalConfig.KeyConfig globalKeyConfig = flexGlobalConfig.getKeyConfig(); 066 KeyType keyType = getKeyType(idInfo, globalKeyConfig); 067 068 if (keyType == null || keyType == KeyType.None) { 069 return NoKeyGenerator.INSTANCE; 070 } 071 072 //自增主键 073 if (keyType == KeyType.Auto) { 074 return Jdbc3KeyGenerator.INSTANCE; 075 } 076 077 //通过 java 生成的主键 078 if (keyType == KeyType.Generator) { 079 return new CustomKeyGenerator(ms.getConfiguration(), tableInfo, idInfo); 080 } 081 082 //通过序列生成的注解 083 String sequence = getKeyValue(idInfo, globalKeyConfig); 084 if (StringUtil.isBlank(sequence)) { 085 throw FlexExceptions.wrap("Please config sequence by @Id(value=\"...\") for field: %s in class: %s" 086 , idInfo.getProperty() 087 , tableInfo.getEntityClass().getName()); 088 } 089 090 091 String selectId = ms.getId() + SelectKeyGenerator.SELECT_KEY_SUFFIX; 092 SqlSource sqlSource = ms.getLang().createSqlSource(ms.getConfiguration(), sequence.trim(), idInfo.getPropertyType()); 093 MappedStatement.Builder msBuilder = new MappedStatement.Builder(ms.getConfiguration(), selectId, sqlSource, SqlCommandType.SELECT) 094 .resource(ms.getResource()) 095 .fetchSize(null) 096 .timeout(null) 097 .statementType(StatementType.PREPARED) 098 .keyGenerator(NoKeyGenerator.INSTANCE) 099 .keyProperty(FlexConsts.ENTITY + "." + idInfo.getProperty()) 100 .keyColumn(idInfo.getColumn()) 101 .databaseId(ms.getDatabaseId()) 102 .lang(ms.getLang()) 103 .resultOrdered(false) 104 .resultSets(null) 105 .resultMaps(createIdResultMaps(ms.getConfiguration(), selectId + "-Inline", idInfo.getPropertyType(), new ArrayList<>())) 106 .resultSetType(null) 107 .flushCacheRequired(false) 108 .useCache(false) 109 .cache(ms.getCache()); 110 111 MappedStatement keyMappedStatement = msBuilder.build(); 112 ms.getConfiguration().addMappedStatement(keyMappedStatement); 113 114 //看到有的框架把 keyGenerator 添加到 mybatis 的当前配置里去,其实是完全没必要的 115 //因为只有在 xml 解析的时候,才可能存在多一个 MappedStatement 拥有同一个 keyGenerator 的情况 116 //当前每个方法都拥有一个自己的 keyGenerator 了,没必要添加 117 //addKeyGenerator(selectId, keyGenerator) 118 return new SelectKeyGenerator(keyMappedStatement, isKeyBefore(idInfo, globalKeyConfig)); 119 } 120 121 122 private static List<ResultMap> createIdResultMaps(Configuration configuration, 123 String statementId, Class<?> resultType, List<ResultMapping> resultMappings) { 124 ResultMap resultMap = new ResultMap.Builder(configuration, statementId, resultType, resultMappings, null) 125 .build(); 126 return Arrays.asList(resultMap); 127 } 128 129 130 /** 131 * 获取主键的 keyType,优先通过 @id 获取,获取不到通过全局配置获取 132 */ 133 public static KeyType getKeyType(IdInfo idInfo, FlexGlobalConfig.KeyConfig globalKeyConfig) { 134 KeyType keyType = idInfo.getKeyType(); 135 if (keyType != KeyType.None) { 136 return keyType; 137 } 138 139 if (globalKeyConfig != null) { 140 return globalKeyConfig.getKeyType(); 141 } 142 143 return keyType; 144 } 145 146 147 public static String getKeyValue(IdInfo idInfo, FlexGlobalConfig.KeyConfig globalKeyConfig) { 148 String value = idInfo.getValue(); 149 if (StringUtil.isBlank(value) && globalKeyConfig != null) { 150 value = globalKeyConfig.getValue(); 151 } 152 return value; 153 } 154 155 156 public static boolean isKeyBefore(IdInfo idInfo, FlexGlobalConfig.KeyConfig globalKeyConfig) { 157 Boolean before = idInfo.getBefore(); 158 if (before == null && globalKeyConfig != null) { 159 return globalKeyConfig.isBefore(); 160 } else { 161 return before == null || before; 162 } 163 } 164 165}