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