package com.project.base.config; import com.baomidou.mybatisplus.core.injector.AbstractMethod; import com.baomidou.mybatisplus.core.metadata.TableInfo; import com.baomidou.mybatisplus.core.metadata.TableFieldInfo; import org.apache.ibatis.executor.keygen.NoKeyGenerator; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.mapping.SqlSource; import java.util.stream.Collectors; /** * 自定义选装件:MySQL 批量 Upsert */ public class InsertBatchOnDuplicateKeyUpdate extends AbstractMethod { protected InsertBatchOnDuplicateKeyUpdate() { super("batchUpsert"); // 方法名 } @Override public MappedStatement injectMappedStatement(Class mapperClass, Class modelClass, TableInfo tableInfo) { final String methodName = "batchUpsert"; // 1. 准备 INSERT 字段 String columnScript = "(" + tableInfo.getKeyColumn() + "," + tableInfo.getFieldList().stream() .map(TableFieldInfo::getColumn) .collect(Collectors.joining(",")) + ")"; // 2. 准备 VALUES 部分 (处理逻辑删除位) String valuesScript = "(#{item." + tableInfo.getKeyProperty() + "}," + tableInfo.getFieldList().stream() .map(i -> { // A. 如果是逻辑删除字段:处理“没传就默认 0” if (i.isLogicDelete()) { // 使用 IFNULL 保证如果 Java 对象里 deleted 是 null,数据库填入 0 return "IFNULL(#{item." + i.getProperty() + "}, 0)"; } // B. 处理 TypeHandler (如之前处理的 JSON 字段) if (i.getTypeHandler() != null) { return "#{item." + i.getProperty() + ",typeHandler=" + i.getTypeHandler().getName() + "}"; } // C. 普通字段 return "#{item." + i.getProperty() + "}"; }) .collect(Collectors.joining(",")) + ")"; // 3. 准备 ON DUPLICATE KEY UPDATE 部分 String updateScript = tableInfo.getFieldList().stream() // 排除主键和创建时间 .filter(i -> !i.getColumn().equals("create_time")) .map(i -> { // 如果是逻辑删除位,在更新时强制置为 0(即复活数据) // 理由:全量同步中,只要数据还在钉钉列表里,就说明该部门/人员是活跃的 if (i.isLogicDelete()) { return i.getColumn() + " = 0"; } // 其他字段正常更新 return i.getColumn() + " = VALUES(" + i.getColumn() + ")"; }) .collect(Collectors.joining(",")) + ", update_time = NOW()"; String sql = String.format("", tableInfo.getTableName(), columnScript, valuesScript, updateScript); SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass); return this.addInsertMappedStatement(mapperClass, modelClass, methodName, sqlSource, new NoKeyGenerator(), null, null); } }