浏览代码

优化一下乐观锁

miemie 5 年之前
父节点
当前提交
e8a6bdd710

+ 2 - 0
mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/metadata/TableFieldInfo.java

@@ -152,6 +152,7 @@ public class TableFieldInfo implements Constants {
      */
     @SuppressWarnings("unchecked")
     public TableFieldInfo(GlobalConfig.DbConfig dbConfig, TableInfo tableInfo, Field field, TableField tableField) {
+        field.setAccessible(true);
         this.field = field;
         this.version = field.getAnnotation(Version.class) != null;
         this.property = field.getName();
@@ -245,6 +246,7 @@ public class TableFieldInfo implements Constants {
      * 不存在 TableField 注解时, 使用的构造函数
      */
     public TableFieldInfo(GlobalConfig.DbConfig dbConfig, TableInfo tableInfo, Field field) {
+        field.setAccessible(true);
         this.field = field;
         this.version = field.getAnnotation(Version.class) != null;
         this.property = field.getName();

+ 9 - 0
mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/metadata/TableInfo.java

@@ -152,6 +152,14 @@ public class TableInfo implements Constants {
     @Getter
     @Setter(AccessLevel.NONE)
     private boolean enableVersion;
+    /**
+     * 表字段是否启用了乐观锁
+     *
+     * @since 3.3.1
+     */
+    @Getter
+    @Setter(AccessLevel.NONE)
+    private TableFieldInfo versionFieldInfo;
 
     public TableInfo(Class<?> entityType) {
         this.entityType = entityType;
@@ -416,6 +424,7 @@ public class TableInfo implements Constants {
             }
             if (i.isVersion()) {
                 this.enableVersion = true;
+                this.versionFieldInfo = i;
             }
         });
     }

+ 22 - 76
mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/plugins/OptimisticLockerInterceptor.java

@@ -22,9 +22,7 @@ import com.baomidou.mybatisplus.core.metadata.TableFieldInfo;
 import com.baomidou.mybatisplus.core.metadata.TableInfo;
 import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
 import com.baomidou.mybatisplus.core.toolkit.Constants;
-import com.baomidou.mybatisplus.core.toolkit.ReflectionKit;
 import com.baomidou.mybatisplus.core.toolkit.StringPool;
-import lombok.Data;
 import org.apache.ibatis.executor.Executor;
 import org.apache.ibatis.mapping.MappedStatement;
 import org.apache.ibatis.mapping.SqlCommandType;
@@ -33,9 +31,10 @@ import org.apache.ibatis.plugin.*;
 import java.lang.reflect.Field;
 import java.sql.Timestamp;
 import java.time.LocalDateTime;
-import java.util.*;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.stream.Collectors;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
 
 /**
  * Optimistic Lock Light version
@@ -61,8 +60,6 @@ import java.util.stream.Collectors;
 public class OptimisticLockerInterceptor implements Interceptor {
 
     private static final String PARAM_UPDATE_METHOD_NAME = "update";
-    private final Map<Class<?>, EntityField> versionFieldCache = new ConcurrentHashMap<>();
-    private final Map<Class<?>, List<EntityField>> entityFieldsCache = new ConcurrentHashMap<>();
 
     @Override
     @SuppressWarnings({"unchecked", "rawtypes"})
@@ -76,7 +73,7 @@ public class OptimisticLockerInterceptor implements Interceptor {
         if (param instanceof Map) {
             Map map = (Map) param;
             //updateById(et), update(et, wrapper);
-            Object et = map.getOrDefault(Constants.ENTITY, null);
+            Object et = map.get(Constants.ENTITY);
             if (et != null) {
                 // entity
                 String methodId = ms.getId();
@@ -86,38 +83,32 @@ public class OptimisticLockerInterceptor implements Interceptor {
                 if (tableInfo == null || !tableInfo.isEnableVersion()) {
                     return invocation.proceed();
                 }
-                EntityField versionField = this.getVersionField(entityClass, tableInfo);
-                if (versionField == null) {
-                    return invocation.proceed();
-                }
-                Field field = versionField.getField();
-                Object originalVersionVal = versionField.getField().get(et);
+                TableFieldInfo fieldInfo = tableInfo.getVersionFieldInfo();
+                final String versionColumn = fieldInfo.getColumn();
+                final Field versionField = fieldInfo.getField();
+                Object originalVersionVal = versionField.get(et);
                 if (originalVersionVal == null) {
                     return invocation.proceed();
                 }
-                Object updatedVersionVal = getUpdatedVersionVal(originalVersionVal);
+                final Object updatedVersionVal = this.getUpdatedVersionVal(fieldInfo.getPropertyType(), originalVersionVal);
                 if (PARAM_UPDATE_METHOD_NAME.equals(methodName)) {
                     // update(entity, wrapper)
                     // mapper.update(updEntity, QueryWrapper<>(whereEntity);
                     AbstractWrapper<?, ?, ?> ew = (AbstractWrapper<?, ?, ?>) map.getOrDefault(Constants.WRAPPER, null);
                     if (ew == null) {
                         UpdateWrapper<?> uw = new UpdateWrapper<>();
-                        uw.eq(versionField.getColumnName(), originalVersionVal);
+                        uw.eq(versionColumn, originalVersionVal);
                         map.put(Constants.WRAPPER, uw);
-                        field.set(et, updatedVersionVal);
+                        versionField.set(et, updatedVersionVal);
                     } else {
-                        ew.apply(versionField.getColumnName() + " = {0}", originalVersionVal);
-                        field.set(et, updatedVersionVal);
+                        ew.apply(versionColumn + " = {0}", originalVersionVal);
+                        versionField.set(et, updatedVersionVal);
                         //TODO: should remove version=oldval condition from aw; 0827 by k神
                     }
                     return invocation.proceed();
                 } else {
-                    List<EntityField> fields = entityFieldsCache.computeIfAbsent(entityClass, this::getFieldsFromClazz);
                     Map<String, Object> entityMap = new HashMap<>(3);
-                    String versionColumnName = versionField.getColumnName();
-                    //update to cache
-                    versionField.setColumnName(versionColumnName);
-                    entityMap.put(Constants.MP_OPTLOCK_VERSION_COLUMN, versionColumnName);
+                    entityMap.put(Constants.MP_OPTLOCK_VERSION_COLUMN, versionColumn);
                     entityMap.put(Constants.MP_OPTLOCK_VERSION_ORIGINAL, originalVersionVal);
                     map.put(Constants.MP_OPTLOCK_INTERCEPTOR, entityMap);
                     Object resultObj = invocation.proceed();
@@ -125,7 +116,7 @@ public class OptimisticLockerInterceptor implements Interceptor {
                         Integer effRow = (Integer) resultObj;
                         if (updatedVersionVal != null && effRow != 0) {
                             //updated version value set to entity.
-                            field.set(et, updatedVersionVal);
+                            versionField.set(et, updatedVersionVal);
                         }
                     }
                     return resultObj;
@@ -142,17 +133,16 @@ public class OptimisticLockerInterceptor implements Interceptor {
      * @param originalVersionVal ignore
      * @return updated version val
      */
-    protected Object getUpdatedVersionVal(Object originalVersionVal) {
-        Class<?> versionValClass = originalVersionVal.getClass();
-        if (long.class.equals(versionValClass) || Long.class.equals(versionValClass)) {
+    protected Object getUpdatedVersionVal(Class<?> clazz, Object originalVersionVal) {
+        if (long.class.equals(clazz) || Long.class.equals(clazz)) {
             return ((long) originalVersionVal) + 1;
-        } else if (int.class.equals(versionValClass) || Integer.class.equals(versionValClass)) {
+        } else if (int.class.equals(clazz) || Integer.class.equals(clazz)) {
             return ((int) originalVersionVal) + 1;
-        } else if (Date.class.equals(versionValClass)) {
+        } else if (Date.class.equals(clazz)) {
             return new Date();
-        } else if (Timestamp.class.equals(versionValClass)) {
+        } else if (Timestamp.class.equals(clazz)) {
             return new Timestamp(System.currentTimeMillis());
-        } else if (LocalDateTime.class.equals(versionValClass)) {
+        } else if (LocalDateTime.class.equals(clazz)) {
             return LocalDateTime.now();
         }
         //not supported type, return original val.
@@ -171,48 +161,4 @@ public class OptimisticLockerInterceptor implements Interceptor {
     public void setProperties(Properties properties) {
         // to do nothing
     }
-
-    private EntityField getVersionField(Class<?> parameterClass, TableInfo tableInfo) {
-        return versionFieldCache.computeIfAbsent(parameterClass, mapping -> getVersionFieldRegular(mapping, tableInfo));
-    }
-
-    /**
-     * 反射检查参数类是否启动乐观锁
-     *
-     * @param parameterClass 实体类
-     * @param tableInfo      实体数据库反射信息
-     * @return ignore
-     */
-    private EntityField getVersionFieldRegular(Class<?> parameterClass, TableInfo tableInfo) {
-        return Object.class.equals(parameterClass) ? null : ReflectionKit.getFieldList(parameterClass).stream().filter(e -> e.isAnnotationPresent(Version.class)).map(field -> {
-            field.setAccessible(true);
-            return new EntityField(field, true, tableInfo.getFieldList().stream().filter(e -> field.getName().equals(e.getProperty())).map(TableFieldInfo::getColumn).findFirst().orElse(null));
-        }).findFirst().orElseGet(() -> this.getVersionFieldRegular(parameterClass.getSuperclass(), tableInfo));
-    }
-
-    private List<EntityField> getFieldsFromClazz(Class<?> parameterClass) {
-        return ReflectionKit.getFieldList(parameterClass).stream().map(field -> {
-            field.setAccessible(true);
-            return new EntityField(field, field.isAnnotationPresent(Version.class));
-        }).collect(Collectors.toList());
-    }
-
-    @Data
-    private class EntityField {
-
-        private Field field;
-        private boolean version;
-        private String columnName;
-
-        EntityField(Field field, boolean version) {
-            this.field = field;
-            this.version = version;
-        }
-
-        public EntityField(Field field, boolean version, String columnName) {
-            this.field = field;
-            this.version = version;
-            this.columnName = columnName;
-        }
-    }
 }