瀏覽代碼

重构初始化 TableInfo -> ColumnCache 部分缓存问题,将“找不到字段抛异常”降级“为返回 null”

hcl 6 年之前
父節點
當前提交
8bfb664cad

+ 7 - 20
mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/conditions/AbstractLambdaWrapper.java

@@ -15,14 +15,14 @@
  */
 package com.baomidou.mybatisplus.core.conditions;
 
-import com.baomidou.mybatisplus.core.toolkit.*;
+import com.baomidou.mybatisplus.core.toolkit.LambdaUtils;
+import com.baomidou.mybatisplus.core.toolkit.StringPool;
+import com.baomidou.mybatisplus.core.toolkit.StringUtils;
 import com.baomidou.mybatisplus.core.toolkit.support.ColumnCache;
 import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
 import com.baomidou.mybatisplus.core.toolkit.support.SerializedLambda;
 
 import java.util.Arrays;
-import java.util.Locale;
-import java.util.Map;
 import java.util.Optional;
 
 import static java.util.stream.Collectors.joining;
@@ -38,20 +38,13 @@ import static java.util.stream.Collectors.joining;
 public abstract class AbstractLambdaWrapper<T, Children extends AbstractLambdaWrapper<T, Children>>
     extends AbstractWrapper<T, SFunction<T, ?>, Children> {
 
-    private Map<String, ColumnCache> columnMap = null;
-    private boolean initColumnMap = false;
-
     @Override
     protected void initEntityClass() {
         super.initEntityClass();
-        if (entityClass != null) {
-            columnMap = LambdaUtils.getColumnMap(entityClass.getName());
-            initColumnMap = true;
-        }
     }
 
     @SuppressWarnings("unchecked")
-	@Override
+    @Override
     protected String columnsToString(SFunction<T, ?>... columns) {
         return columnsToString(true, columns);
     }
@@ -72,15 +65,9 @@ public abstract class AbstractLambdaWrapper<T, Children extends AbstractLambdaWr
 
     private String getColumn(SerializedLambda lambda, boolean onlyColumn) {
         String fieldName = StringUtils.resolveFieldName(lambda.getImplMethodName());
-        if (!initColumnMap || !columnMap.containsKey(fieldName.toUpperCase(Locale.ENGLISH))) {
-            String entityClassName = lambda.getImplClassName();
-            columnMap = LambdaUtils.getColumnMap(entityClassName);
-            Assert.notEmpty(columnMap, "cannot find column's cache for \"%s\", so you cannot used \"%s\"!",
-                entityClassName, typedThis.getClass());
-            initColumnMap = true;
-        }
-        return Optional.ofNullable(columnMap.get(fieldName.toUpperCase(Locale.ENGLISH)))
+        return Optional.ofNullable(LambdaUtils.getColumnOfProperty(entityClass, fieldName))
             .map(onlyColumn ? ColumnCache::getColumn : ColumnCache::getColumnSelect)
-            .orElseThrow(() -> ExceptionUtils.mpe("your property named \"%s\" cannot find the corresponding database column name!", fieldName));
+            .orElse(null);
     }
+
 }

+ 38 - 37
mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/toolkit/LambdaUtils.java

@@ -22,7 +22,6 @@ import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
 import com.baomidou.mybatisplus.core.toolkit.support.SerializedLambda;
 
 import java.lang.ref.WeakReference;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Optional;
@@ -33,12 +32,15 @@ import static java.util.Locale.ENGLISH;
 /**
  * Lambda 解析工具类
  *
- * @author HCL
+ * @author HCL, MieMie
  * @since 2018-05-10
  */
 public final class LambdaUtils {
 
-    private static final Map<String, Map<String, ColumnCache>> LAMBDA_CACHE = new ConcurrentHashMap<>();
+    /**
+     * 字段映射
+     */
+    private static final Map<Class<?>, Map<String, ColumnCache>> LAMBDA_MAP = new ConcurrentHashMap<>();
 
     /**
      * SerializedLambda 反序列化缓存
@@ -64,62 +66,61 @@ public final class LambdaUtils {
     }
 
     /**
-     * 缓存实体类名与表字段映射关系
+     * 将传入的表信息加入缓存
      *
-     * @param clazz     实体
      * @param tableInfo 表信息
      */
-    public static void createCache(Class<?> clazz, TableInfo tableInfo) {
-        LAMBDA_CACHE.put(clazz.getName(), createLambdaMap(tableInfo, clazz));
+    public static void installCache(TableInfo tableInfo) {
+        LAMBDA_MAP.put(tableInfo.getClazz(), createColumnCacheMap(tableInfo));
     }
 
     /**
      * 缓存实体字段 MAP 信息
      *
-     * @param tableInfo 表信息
+     * @param info 表信息
      * @return 缓存 map
      */
-    private static Map<String, ColumnCache> createLambdaMap(TableInfo tableInfo, Class<?> clazz) {
+    private static Map<String, ColumnCache> createColumnCacheMap(TableInfo info) {
         Map<String, ColumnCache> map = new HashMap<>();
-        String keyProperty = tableInfo.getKeyProperty();
-        if (StringUtils.isNotEmpty(keyProperty)) {
-            saveCacheAndPut(tableInfo.getKeyColumn(), tableInfo.getKeySqlSelect(), keyProperty.toUpperCase(ENGLISH),
-                clazz, tableInfo.getClazz(), map);
-        }
-        tableInfo.getFieldList().forEach(i -> saveCacheAndPut(i.getColumn(), i.getSqlSelect(tableInfo.getDbType()),
-            i.getProperty().toUpperCase(ENGLISH), clazz, i.getClazz(), map));
-        return map;
-    }
 
-    private static void saveCacheAndPut(String column, String select, String property, Class<?> entityClass,
-                                        Class<?> propertyAffiliationClass, Map<String, ColumnCache> map) {
-        ColumnCache cache = new ColumnCache(column, select);
-        if (propertyAffiliationClass != entityClass) {
-            saveCache(propertyAffiliationClass.getName(), property, cache);
+        String kp = info.getKeyProperty();
+        if (null != kp) {
+            map.put(formatKey(kp), new ColumnCache(info.getKeyColumn(), info.getKeySqlSelect()));
         }
-        map.put(property, cache);
+
+        info.getFieldList().forEach(i ->
+            map.put(formatKey(i.getProperty()), new ColumnCache(i.getColumn(), i.getSqlSelect(info.getDbType())))
+        );
+        return map;
     }
 
     /**
-     * 保存缓存信息
+     * 格式化 key 将传入的 key 变更为大写格式
+     *
+     * <pre>
+     *     Assert.assertEquals("USERID", formatKey("userId"))
+     * </pre>
      *
-     * @param className   类名
-     * @param property    属性
-     * @param columnCache 字段信息
+     * @param key key
+     * @return 大写的 key
      */
-    private static void saveCache(String className, String property, ColumnCache columnCache) {
-        Map<String, ColumnCache> cacheMap = LAMBDA_CACHE.getOrDefault(className, new HashMap<>());
-        cacheMap.put(property, columnCache);
-        LAMBDA_CACHE.put(className, cacheMap);
+    private static String formatKey(String key) {
+        return key.toUpperCase(ENGLISH);
     }
 
     /**
-     * 获取实体对应字段 MAP
+     * 获取 clazz 中某字段对应的列信息
      *
-     * @param entityClassName 实体类名
-     * @return 缓存 map
+     * @param clazz     class 类
+     * @param fieldName 字段名称
+     * @return 如果存在,返回字段信息;否则返回 null
      */
-    public static Map<String, ColumnCache> getColumnMap(String entityClassName) {
-        return LAMBDA_CACHE.getOrDefault(entityClassName, Collections.emptyMap());
+    public static ColumnCache getColumnOfProperty(Class<?> clazz, String fieldName) {
+        Map<String, ColumnCache> map = LAMBDA_MAP.get(clazz);
+        if (null != map) {
+            return map.get(formatKey(fieldName));
+        }
+        return null;
     }
+
 }

+ 14 - 19
mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/toolkit/TableInfoHelper.java

@@ -15,15 +15,11 @@
  */
 package com.baomidou.mybatisplus.core.toolkit;
 
-import static java.util.stream.Collectors.toList;
-
-import java.lang.reflect.Field;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
+import com.baomidou.mybatisplus.annotation.*;
+import com.baomidou.mybatisplus.core.config.GlobalConfig;
+import com.baomidou.mybatisplus.core.incrementer.IKeyGenerator;
+import com.baomidou.mybatisplus.core.metadata.TableFieldInfo;
+import com.baomidou.mybatisplus.core.metadata.TableInfo;
 import org.apache.ibatis.builder.MapperBuilderAssistant;
 import org.apache.ibatis.executor.keygen.KeyGenerator;
 import org.apache.ibatis.executor.keygen.NoKeyGenerator;
@@ -36,15 +32,14 @@ import org.apache.ibatis.mapping.SqlSource;
 import org.apache.ibatis.mapping.StatementType;
 import org.apache.ibatis.scripting.LanguageDriver;
 
-import com.baomidou.mybatisplus.annotation.IdType;
-import com.baomidou.mybatisplus.annotation.KeySequence;
-import com.baomidou.mybatisplus.annotation.TableField;
-import com.baomidou.mybatisplus.annotation.TableId;
-import com.baomidou.mybatisplus.annotation.TableName;
-import com.baomidou.mybatisplus.core.config.GlobalConfig;
-import com.baomidou.mybatisplus.core.incrementer.IKeyGenerator;
-import com.baomidou.mybatisplus.core.metadata.TableFieldInfo;
-import com.baomidou.mybatisplus.core.metadata.TableInfo;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import static java.util.stream.Collectors.toList;
 
 /**
  * <p>
@@ -147,7 +142,7 @@ public class TableInfoHelper {
         TABLE_INFO_CACHE.put(clazz, tableInfo);
 
         /* 缓存 Lambda 映射关系 */
-        LambdaUtils.createCache(clazz, tableInfo);
+        LambdaUtils.installCache(tableInfo);
         return tableInfo;
     }
 

+ 6 - 19
mybatis-plus-extension/src/main/kotlin/com/baomidou/mybatisplus/extension/kotlin/AbstractKtWrapper.kt

@@ -18,8 +18,6 @@ package com.baomidou.mybatisplus.extension.kotlin
 import com.baomidou.mybatisplus.core.conditions.AbstractWrapper
 import com.baomidou.mybatisplus.core.toolkit.LambdaUtils
 import com.baomidou.mybatisplus.core.toolkit.StringPool
-import com.baomidou.mybatisplus.core.toolkit.support.ColumnCache
-import java.util.*
 import kotlin.reflect.KProperty
 
 /**
@@ -32,18 +30,11 @@ import kotlin.reflect.KProperty
  */
 abstract class AbstractKtWrapper<T, Children : AbstractKtWrapper<T, Children>> : AbstractWrapper<T, KProperty<*>, Children>() {
 
-    /**
-     * 列 Map
-     */
-    private lateinit var columnMap: Map<String, ColumnCache>
-
     /**
      * 为了兼容 [AbstractWrapper.columnToString] 的方法,重载该方法
      * 因为 Java 并不支持参数默认值,这里只能妥协
      */
-    override fun columnToString(column: KProperty<*>?): String? {
-        return column?.let { columnToString(column) }
-    }
+    override fun columnToString(column: KProperty<*>?): String? = column?.let { columnToString(column, true) }
 
     /**
      * 将某一列转换为对应的数据库字符串, 将 DTO 中的字段 [kProperty] 转换为对应 SQL 语句中的形式
@@ -58,19 +49,15 @@ abstract class AbstractKtWrapper<T, Children : AbstractKtWrapper<T, Children>> :
      *</pre>
      *
      */
-    fun columnToString(kProperty: KProperty<*>, onlyColumn: Boolean = true): String? {
-        if (!::columnMap.isInitialized) {
-            columnMap = LambdaUtils.getColumnMap(this.checkEntityClass.name)
-        }
-        return columnMap[kProperty.name.toUpperCase(Locale.ENGLISH)]?.let { if (onlyColumn) it.column else it.columnSelect }
-    }
+    fun columnToString(kProperty: KProperty<*>, onlyColumn: Boolean = true): String? =
+        LambdaUtils.getColumnOfProperty(entityClass, kProperty.name)?.let { if (onlyColumn) it.column else it.columnSelect }
 
     /**
      * 批量处理传入的属性,正常情况下的输出就像:
      *
      * "user_id" AS "userId" , "user_name" AS "userName"
      */
-    fun columnsToString(onlyColumn: Boolean = true, vararg columns: KProperty<*>): String {
-        return columns.mapNotNull { columnToString(it, onlyColumn) }.joinToString(separator = StringPool.COMMA)
-    }
+    fun columnsToString(onlyColumn: Boolean = true, vararg columns: KProperty<*>): String =
+        columns.mapNotNull { columnToString(it, onlyColumn) }.joinToString(separator = StringPool.COMMA)
+
 }