فهرست منبع

Merge remote-tracking branch 'origin/3.0' into 3.0

hubin 1 سال پیش
والد
کامیت
f83af0bca8

+ 74 - 46
mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/plugins/inner/DataChangeRecorderInnerInterceptor.java

@@ -16,7 +16,6 @@
 package com.baomidou.mybatisplus.extension.plugins.inner;
 
 import java.io.Reader;
-import java.math.BigDecimal;
 import java.sql.Clob;
 import java.sql.Connection;
 import java.sql.PreparedStatement;
@@ -25,13 +24,13 @@ import java.sql.ResultSetMetaData;
 import java.sql.SQLException;
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.Date;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.Optional;
 import java.util.Properties;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
@@ -51,6 +50,7 @@ import com.baomidou.mybatisplus.annotation.IEnum;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
 import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
+import com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler;
 import com.baomidou.mybatisplus.core.metadata.TableFieldInfo;
 import com.baomidou.mybatisplus.core.metadata.TableInfo;
 import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
@@ -199,7 +199,8 @@ public class DataChangeRecorderInnerInterceptor implements InnerInterceptor {
         result.setOperation("insert");
         result.setTableName(insertStmt.getTable().getName());
         result.setRecordStatus(true);
-        result.buildDataStr(compareAndGetUpdatedColumnDatas(result.getTableName(), boundSql, insertStmt, null));
+        Map<String, Object> updatedColumnDatas = getUpdatedColumnDatas(result.getTableName(), boundSql, insertStmt);
+        result.buildDataStr(compareAndGetUpdatedColumnDatas(result.getTableName(), null, updatedColumnDatas));
         return result;
     }
 
@@ -238,15 +239,25 @@ public class DataChangeRecorderInnerInterceptor implements InnerInterceptor {
                 boundSql4Select.setAdditionalParameter(ety.getKey(), ety.getValue());
             }
         }
-        OriginalDataObj originalData = buildOriginalObjectData(selectStmt, buildColumns2SelectItems.getPk(), mappedStatement, boundSql4Select, connection);
+        Map<String, Object> updatedColumnDatas = getUpdatedColumnDatas(table.getName(), boundSql, updateStmt);
+        OriginalDataObj originalData = buildOriginalObjectData(updatedColumnDatas, selectStmt, buildColumns2SelectItems.getPk(), mappedStatement, boundSql4Select, connection);
         OperationResult result = new OperationResult();
         result.setOperation("update");
         result.setTableName(table.getName());
         result.setRecordStatus(true);
-        result.buildDataStr(compareAndGetUpdatedColumnDatas(result.getTableName(), boundSql, updateStmt, originalData));
+        result.buildDataStr(compareAndGetUpdatedColumnDatas(result.getTableName(), originalData, updatedColumnDatas));
         return result;
     }
 
+    private TableInfo getTableInfoByTableName(String tableName) {
+        for (TableInfo tableInfo : TableInfoHelper.getTableInfos()) {
+            if (tableName.equalsIgnoreCase(tableInfo.getTableName())) {
+                return tableInfo;
+            }
+        }
+        return null;
+    }
+
     /**
      * 将update SET部分的jdbc参数去除
      *
@@ -268,13 +279,8 @@ public class DataChangeRecorderInnerInterceptor implements InnerInterceptor {
         return originalMappingList.subList(removeParamCount, originalMappingList.size());
     }
 
-    /**
-     * @param updateSql
-     * @param originalDataObj
-     * @return
-     */
-    private List<DataChangedRecord> compareAndGetUpdatedColumnDatas(String tableName, BoundSql updateSql, Statement statement, OriginalDataObj originalDataObj) {
-        Map<String, String> columnNameValMap = new HashMap<>(updateSql.getParameterMappings().size());
+    protected Map<String, Object> getUpdatedColumnDatas(String tableName, BoundSql updateSql, Statement statement) {
+        Map<String, Object> columnNameValMap = new HashMap<>(updateSql.getParameterMappings().size());
         Map<Integer, String> columnSetIndexMap = new HashMap<>(updateSql.getParameterMappings().size());
         List<Column> selectItemsFromUpdateSql = new ArrayList<>();
         if (statement instanceof Update) {
@@ -315,12 +321,17 @@ public class DataChangeRecorderInnerInterceptor implements InnerInterceptor {
                 final String columnName = columnSetIndexMap.getOrDefault(index++, getColumnNameByProperty(propertyNameTrim, tableName));
                 if (relatedColumnsUpperCaseWithoutUnderline.containsKey(propertyNameTrim)) {
                     final String colkey = relatedColumnsUpperCaseWithoutUnderline.get(propertyNameTrim);
-                    final String val = String.valueOf(metaObject.getValue(propertyName));
+                    Object valObj = metaObject.getValue(propertyName);
+                    if (valObj instanceof IEnum) {
+                        valObj = ((IEnum<?>) valObj).getValue();
+                    } else if (valObj instanceof Enum) {
+                        valObj = getEnumValue((Enum) valObj);
+                    }
                     if (columnNameValMap.containsKey(colkey)) {
-                        columnNameValMap.put(relatedColumnsUpperCaseWithoutUnderline.get(propertyNameTrim), String.valueOf(columnNameValMap.get(colkey)).replace("?", val));
+                        columnNameValMap.put(relatedColumnsUpperCaseWithoutUnderline.get(propertyNameTrim), String.valueOf(columnNameValMap.get(colkey)).replace("?", valObj == null ? "" : valObj.toString()));
                     }
                     if (columnName != null && !columnNameValMap.containsKey(columnName)) {
-                        columnNameValMap.put(columnName, val);
+                        columnNameValMap.put(columnName, valObj);
                     }
                 } else {
                     if (columnName != null) {
@@ -332,12 +343,19 @@ public class DataChangeRecorderInnerInterceptor implements InnerInterceptor {
             }
         }
         dealWithUpdateWrapper(columnSetIndexMap, columnNameValMap, updateSql);
+        return columnNameValMap;
+    }
 
+    /**
+     * @param originalDataObj
+     * @return
+     */
+    private List<DataChangedRecord> compareAndGetUpdatedColumnDatas(String tableName, OriginalDataObj originalDataObj, Map<String, Object> columnNameValMap) {
         final Set<String> ignoredColumns = ignoredTableColumns.get(tableName.toUpperCase());
         if (originalDataObj == null || originalDataObj.isEmpty()) {
             DataChangedRecord oneRecord = new DataChangedRecord();
             List<DataColumnChangeResult> updateColumns = new ArrayList<>(columnNameValMap.size());
-            for (Map.Entry<String, String> ety : columnNameValMap.entrySet()) {
+            for (Map.Entry<String, Object> ety : columnNameValMap.entrySet()) {
                 String columnName = ety.getKey();
                 if ((ignoredColumns == null || !ignoredColumns.contains(columnName)) && !ignoreAllColumns.contains(columnName)) {
                     updateColumns.add(DataColumnChangeResult.constrcutByUpdateVal(columnName, ety.getValue()));
@@ -357,8 +375,17 @@ public class DataChangeRecorderInnerInterceptor implements InnerInterceptor {
         return updateDataList;
     }
 
+    private Object getEnumValue(Enum enumVal) {
+        Optional<String> enumValueFieldName = MybatisEnumTypeHandler.findEnumValueFieldName(enumVal.getClass());
+        if (enumValueFieldName.isPresent()) {
+            return SystemMetaObject.forObject(enumVal).getValue(enumValueFieldName.get());
+        }
+        return enumVal;
+
+    }
+
     @SuppressWarnings("rawtypes")
-    private void dealWithUpdateWrapper(Map<Integer, String> columnSetIndexMap, Map<String, String> columnNameValMap, BoundSql updateSql){
+    private void dealWithUpdateWrapper(Map<Integer, String> columnSetIndexMap, Map<String, Object> columnNameValMap, BoundSql updateSql) {
         if (columnSetIndexMap.size() <= columnNameValMap.size()) {
             return;
         }
@@ -507,20 +534,21 @@ public class DataChangeRecorderInnerInterceptor implements InnerInterceptor {
         }
     }
 
-    private OriginalDataObj buildOriginalObjectData(Select selectStmt, Column pk, MappedStatement mappedStatement, BoundSql boundSql, Connection connection) {
+    private OriginalDataObj buildOriginalObjectData(Map<String, Object> updatedColumnDatas, Select selectStmt, Column pk, MappedStatement mappedStatement, BoundSql boundSql, Connection connection) {
         try (PreparedStatement statement = connection.prepareStatement(selectStmt.toString())) {
             DefaultParameterHandler parameterHandler = new DefaultParameterHandler(mappedStatement, boundSql.getParameterObject(), boundSql);
             parameterHandler.setParameters(statement);
             ResultSet resultSet = statement.executeQuery();
             List<DataChangedRecord> originalObjectDatas = new LinkedList<>();
             int count = 0;
+
             while (resultSet.next()) {
                 ++count;
                 if (checkTableBatchLimitExceeded(selectStmt, count)) {
                     logger.error("batch update limit exceed: count={}, BATCH_UPDATE_LIMIT={}", count, BATCH_UPDATE_LIMIT);
                     throw DataUpdateLimitationException.DEFAULT;
                 }
-                originalObjectDatas.add(prepareOriginalDataObj(resultSet, pk));
+                originalObjectDatas.add(prepareOriginalDataObj(updatedColumnDatas, resultSet, pk));
             }
             OriginalDataObj result = new OriginalDataObj();
             result.setOriginalDataObj(originalObjectDatas);
@@ -580,14 +608,20 @@ public class DataChangeRecorderInnerInterceptor implements InnerInterceptor {
      * @return
      * @throws SQLException
      */
-    private DataChangedRecord prepareOriginalDataObj(ResultSet resultSet, Column pk) throws SQLException {
+    private DataChangedRecord prepareOriginalDataObj(Map<String, Object> updatedColumnDatas, ResultSet resultSet, Column pk) throws SQLException {
         final ResultSetMetaData metaData = resultSet.getMetaData();
         int columnCount = metaData.getColumnCount();
         List<DataColumnChangeResult> originalColumnDatas = new LinkedList<>();
         DataColumnChangeResult pkval = null;
         for (int i = 1; i <= columnCount; ++i) {
             String columnName = metaData.getColumnName(i).toUpperCase();
-            DataColumnChangeResult col = DataColumnChangeResult.constrcutByOriginalVal(columnName, resultSet.getObject(i));
+            DataColumnChangeResult col;
+            Object updateVal = updatedColumnDatas.get(columnName);
+            if (updateVal != null && updateVal.getClass().getCanonicalName().startsWith("java.")) {
+                col = DataColumnChangeResult.constrcutByOriginalVal(columnName, resultSet.getObject(i, updateVal.getClass()));
+            } else {
+                col = DataColumnChangeResult.constrcutByOriginalVal(columnName, resultSet.getObject(i));
+            }
             if (pk != null && columnName.equalsIgnoreCase(pk.getColumnName())) {
                 pkval = col;
             } else {
@@ -603,6 +637,7 @@ public class DataChangeRecorderInnerInterceptor implements InnerInterceptor {
         return changedRecord;
     }
 
+
     private Columns2SelectItemsResult buildColumns2SelectItems(String tableName, List<Column> columns) {
         if (columns == null || columns.isEmpty()) {
             return Columns2SelectItemsResult.build(Collections.singletonList(new AllColumns()), 0);
@@ -611,16 +646,15 @@ public class DataChangeRecorderInnerInterceptor implements InnerInterceptor {
         for (Column column : columns) {
             selectItems.add(new SelectExpressionItem(column));
         }
-        for (TableInfo tableInfo : TableInfoHelper.getTableInfos()) {
-            if (tableName.equalsIgnoreCase(tableInfo.getTableName())) {
-                Column pk = new Column(tableInfo.getKeyColumn());
-                selectItems.add(new SelectExpressionItem(pk));
-                Columns2SelectItemsResult result = Columns2SelectItemsResult.build(selectItems, 1);
-                result.setPk(pk);
-                return result;
-            }
+        TableInfo tableInfo = getTableInfoByTableName(tableName);
+        if (tableInfo == null) {
+            return Columns2SelectItemsResult.build(selectItems, 0);
         }
-        return Columns2SelectItemsResult.build(selectItems, 0);
+        Column pk = new Column(tableInfo.getKeyColumn());
+        selectItems.add(new SelectExpressionItem(pk));
+        Columns2SelectItemsResult result = Columns2SelectItemsResult.build(selectItems, 1);
+        result.setPk(pk);
+        return result;
     }
 
     private String buildParameterObject(BoundSql boundSql) {
@@ -815,28 +849,22 @@ public class DataChangeRecorderInnerInterceptor implements InnerInterceptor {
         @SuppressWarnings("rawtypes")
         public boolean isDataChanged(Object updateValue) {
             if (!Objects.equals(originalValue, updateValue)) {
-                if (updateValue instanceof Number && originalValue instanceof Number) {
-                    BigDecimal update = new BigDecimal(updateValue.toString());
-                    BigDecimal original = new BigDecimal(originalValue.toString());
-                    return update.compareTo(original) != 0;
-                }
-                if (updateValue instanceof Date && originalValue instanceof Date) {
-                    Date update = (Date) updateValue;
-                    Date original = (Date) originalValue;
-                    return update.compareTo(original) != 0;
-                }
                 if (originalValue instanceof Clob) {
                     String originalStr = convertClob((Clob) originalValue);
                     setOriginalValue(originalStr);
                     return !originalStr.equals(updateValue);
                 }
+                if (originalValue instanceof Comparable) {
+                    Comparable original = (Comparable) originalValue;
+                    Comparable update = (Comparable) updateValue;
+                    try {
+                        return update == null || original.compareTo(update) != 0;
+                    } catch (Exception e) {
+                        return true;
+                    }
+                }
                 return true;
             }
-            if (originalValue instanceof Comparable) {
-                Comparable original = (Comparable) originalValue;
-                Comparable update = (Comparable) updateValue;
-                return original.compareTo(update) != 0;
-            }
             return false;
         }
 
@@ -895,7 +923,7 @@ public class DataChangeRecorderInnerInterceptor implements InnerInterceptor {
         private List<DataColumnChangeResult> originalColumnDatas;
         private List<DataColumnChangeResult> updatedColumns;
 
-        public boolean hasUpdate(Map<String, String> columnNameValMap, Set<String> ignoredColumns, Set<String> ignoreAllColumns) {
+        public boolean hasUpdate(Map<String, Object> columnNameValMap, Set<String> ignoredColumns, Set<String> ignoreAllColumns) {
             if (originalColumnDatas == null) {
                 return true;
             }

+ 15 - 5
mybatis-plus/src/test/java/com/baomidou/mybatisplus/test/h2/H2UserTest.java

@@ -17,6 +17,7 @@ package com.baomidou.mybatisplus.test.h2;
 
 import java.math.BigDecimal;
 import java.math.RoundingMode;
+import java.time.LocalDateTime;
 import java.util.AbstractList;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -204,21 +205,29 @@ class H2UserTest extends BaseTest {
         user.setDesc("asdf");
         user.setTestType(1);
         user.setVersion(1);
+        final LocalDateTime dateTime = LocalDateTime.of(2024, 3, 29, 10, 0, 0);
+        user.setCreatedDt(dateTime);
         userService.save(user);
 
         H2User userDB = userService.getById(id);
         Assertions.assertEquals(1, userDB.getVersion().intValue());
+        Assertions.assertTrue(userDB.getCreatedDt().compareTo(dateTime) == 0);
 
         userDB.setName("992");
+        userDB.setCreatedDt(dateTime);
+        System.out.println("===============================================");
         userService.updateById(userDB);
         Assertions.assertEquals(2, userDB.getVersion().intValue(), "updated version value should be updated to entity");
 
         userDB = userService.getById(id);
         Assertions.assertEquals(2, userDB.getVersion().intValue());
         Assertions.assertEquals("992", userDB.getName());
-        userService.lambdaUpdate().set(H2User::getAge,AgeEnum.THREE).eq(H2User::getTestId,id).update();
+        userDB.setCreatedDt(LocalDateTime.now());
+        userService.updateById(userDB);
+        System.out.println("===============================================");
+        userService.lambdaUpdate().set(H2User::getAge, AgeEnum.THREE).eq(H2User::getTestId, id).update();
         UpdateWrapper<H2User> wp = new UpdateWrapper<>();
-        wp.set("age",AgeEnum.TWO).eq("test_id",id);
+        wp.set("age", AgeEnum.TWO);
         wp.set("name", "yanjinyin@gitee");
         userService.update(wp);
 
@@ -507,12 +516,10 @@ class H2UserTest extends BaseTest {
         final Select select = (Select) CCJSqlParserUtil.parse(targetSql1);
         Assertions.assertEquals(select.toString(), targetSql1);
 
-
         final String targetSql2 = "SELECT * FROM user WHERE id NOT IN (?)";
         final Select select2 = (Select) CCJSqlParserUtil.parse(targetSql2);
         Assertions.assertEquals(select2.toString(), targetSql2);
 
-
         final String targetSql3 = "SELECT * FROM user WHERE id IS NOT NULL";
         final Select select3 = (Select) CCJSqlParserUtil.parse(targetSql3);
         Assertions.assertEquals(select3.toString(), targetSql3);
@@ -868,16 +875,19 @@ class H2UserTest extends BaseTest {
                 System.out.println("-------处理OrderByDesc----------");
                 return super.doOrderByDesc(condition, column, columns);
             }
+
             @Override
-            protected LambdaQueryChainWrapper<H2User> doOrderByAsc(boolean condition, SFunction<H2User, ?> column,  List<SFunction<H2User, ?>> columns) {
+            protected LambdaQueryChainWrapper<H2User> doOrderByAsc(boolean condition, SFunction<H2User, ?> column, List<SFunction<H2User, ?>> columns) {
                 System.out.println("-------处理OrderByAsc----------");
                 return super.doOrderByAsc(condition, column, columns);
             }
+
             @Override
             protected LambdaQueryChainWrapper<H2User> doOrderBy(boolean condition, boolean isAsc, SFunction<H2User, ?> column, List<SFunction<H2User, ?>> columns) {
                 System.out.println("-------处理OrderBy----------");
                 return super.doOrderBy(condition, isAsc, column, columns);
             }
+
             @Override
             protected LambdaQueryChainWrapper<H2User> doGroupBy(boolean condition, SFunction<H2User, ?> column, List<SFunction<H2User, ?>> columns) {
                 System.out.println("-------处理GroupBy----------");

+ 8 - 3
mybatis-plus/src/test/java/com/baomidou/mybatisplus/test/h2/entity/H2User.java

@@ -15,19 +15,21 @@
  */
 package com.baomidou.mybatisplus.test.h2.entity;
 
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+import java.util.Date;
+
 import com.baomidou.mybatisplus.annotation.FieldFill;
 import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableLogic;
 import com.baomidou.mybatisplus.annotation.TableName;
 import com.baomidou.mybatisplus.annotation.Version;
 import com.baomidou.mybatisplus.test.h2.enums.AgeEnum;
+
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 import lombok.experimental.Accessors;
 
-import java.math.BigDecimal;
-import java.util.Date;
-
 /**
  * 测试用户类
  *
@@ -75,6 +77,9 @@ public class H2User extends SuperEntity {
     @TableLogic
     private Integer deleted;
 
+    @TableField("created_dt")
+    private LocalDateTime createdDt;
+
 
     public H2User() {
 

+ 1 - 0
mybatis-plus/src/test/resources/h2/user.ddl.sql

@@ -7,6 +7,7 @@ CREATE TABLE IF NOT EXISTS  h2user (
 	price DECIMAL(10,2) NULL DEFAULT NULL,
 	desc VARCHAR(30) NULL DEFAULT NULL ,
 	version INT(5) NULL DEFAULT NULL,
+	created_dt TIMESTAMP NULL,
 	last_updated_dt TIMESTAMP NULL,
 	deleted INT(1) NULL DEFAULT 0 ,
 	PRIMARY KEY (test_id)