将POJO类对象转换为insert语句

190 阅读2分钟

1. 场景需求

接上回如果mybatis-plus需要物理删除的时候,之前发生过一个场景,不小心将客户的数据删除了且回滚非常麻烦,为了防止下次再次出现这种问题,一种是通过binlog将delete语句转成insert,但是如果要将这个功能做成需求,让交付进行操作,那么用binlog就比较麻烦。那么可否用java就进行该操作?

2. 功能实现

1.写一个SqlInstanceUtils工具类

public class SqlInstanceUtils {
    /**
     * 生成插入语句(insert into table_name (column_name1,column_name2, ...) values (value1,value2, ...))
     *
     * @param t 有数据的实体
     */
    public static <T> String getInsertSql(T t) {
        String sql;
        String tableName = t.getClass().getAnnotation(TableName.class).value();
        Field[] fields = ReflectUtil.getFieldsDirectly(t.getClass(), true);
        StringBuilder topHalf = new StringBuilder("insert into " + tableName + " (");
        StringBuilder afterHalf = new StringBuilder("values (");
        for (Field field : fields) {
            if (Modifier.isStatic(field.getModifiers())) {
                continue;
            }
            TableField tableField = field.getAnnotation(TableField.class);
            if (tableField != null && !tableField.exist()) {
                continue;
            }
            topHalf.append(tableField != null && StrUtil.isNotEmpty(tableField.value()) ? tableField.value() : StrUtil.toUnderlineCase(field.getName())).append(",");
            if (ReflectUtil.getFieldValue(t, field.getName()) instanceof String) {
                afterHalf.append("'").append(ReflectUtil.getFieldValue(t, field.getName())).append("',");
            } else {
                afterHalf.append(ReflectUtil.getFieldValue(t, field.getName())).append(",");
            }
        }
        topHalf = new StringBuilder(StrUtil.removeSuffix(topHalf.toString(), ","));
        afterHalf = new StringBuilder(StrUtil.removeSuffix(afterHalf.toString(), ","));
        topHalf.append(")");
        afterHalf.append(");");
        sql = topHalf.toString() + afterHalf.toString();
        return sql;
    }

    /**
     * 生成插入语句(insert into table_name (column_name1,column_name2, ...) values (value1,value2, ...),(value1,value2, ...))
     *
     * @param list 有数据的列表
     */
    public static <T> String getInsertBatchSql(List<T> list) {
        if (CollUtil.isEmpty(list)) {
            return "";
        }
        String sql;
        T t = list.get(0);
        String tableName = t.getClass().getAnnotation(TableName.class).value();
        Field[] fields = ReflectUtil.getFieldsDirectly(t.getClass(), true);
        StringBuilder topHalf = new StringBuilder("insert into " + tableName + " (");
        StringBuilder afterHalf = new StringBuilder("values");
        for (Field field : fields) {
            if (Modifier.isStatic(field.getModifiers())) {
                continue;
            }
            TableField tableField = field.getAnnotation(TableField.class);
            if (tableField != null && !tableField.exist()) {
                continue;
            }
            topHalf.append(tableField != null && StrUtil.isNotEmpty(tableField.value()) ? tableField.value() : StrUtil.toUnderlineCase(field.getName())).append(",");
        }
        afterHalf.append(list.stream().map(s -> {
            StringBuilder stringBuilder = new StringBuilder(" (");
            for (Field field : fields) {
                if (Modifier.isStatic(field.getModifiers())) {
                    continue;
                }
                TableField tableField = field.getAnnotation(TableField.class);
                if (tableField != null && !tableField.exist()) {
                    continue;
                }
                Object fieldValue = ReflectUtil.getFieldValue(s, field.getName());
                if (fieldValue instanceof String || fieldValue instanceof LocalDateTime || fieldValue instanceof LocalDate || fieldValue instanceof LocalTime) {
                    stringBuilder.append("'").append(ReflectUtil.getFieldValue(s, field.getName())).append("',");
                } else {
                    stringBuilder.append(ReflectUtil.getFieldValue(s, field.getName())).append(",");
                }
            }
            stringBuilder = new StringBuilder(StrUtil.removeSuffix(stringBuilder.toString(), ","));
            return stringBuilder.append(")");
        }).collect(Collectors.joining(",")));
        topHalf = new StringBuilder(StrUtil.removeSuffix(topHalf.toString(), ","));
        afterHalf = new StringBuilder(StrUtil.removeSuffix(afterHalf.toString(), ","));
        topHalf.append(")");
        afterHalf.append(";");
        sql = topHalf.toString() + afterHalf.toString();
        return sql;
    }
}

2. 如果物理删除每次都需要先查询出来的话使用就比较麻烦,所以我将查询的逻辑封装到一个BaseMapperX接口中,该接口继承了BaseMapper,并且新增了两个default方法,只需要传入StringBuilder对象即可

public interface BaseMapperX<T> extends BaseMapper<T> { 
    int deleteAbsoluteById(Serializable id); 
    int deleteAbsoluteById(T entity); 
    int deleteAbsolute(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper); 
    int deleteAbsoluteBatchByIds(@Param(Constants.COLL) Collection<?> idList); 

    default void deleteAbsolute(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper, StringBuilder sb){
        List<T> ts = selectList(queryWrapper);
        sb.append(SqlInstanceUtils.getInsertBatchSql(ts)).append("\n");
        deleteAbsolute(queryWrapper);
    }

    @SuppressWarnings("unchecked")
    default void deleteAbsoluteBatchByIdList(Collection<?> idList, StringBuilder sb) {
        if (CollUtil.isNotEmpty(idList)) {
            List<T> ts = selectBatchIds((Collection<? extends Serializable>) idList);
            sb.append(SqlInstanceUtils.getInsertBatchSql(ts)).append("\n");
            deleteAbsoluteBatchByIds(idList);
        }
    }
}

3. 最后处理StringBuilder,写入到File中,或者上传到oss即可。

File file = null;
try {
    file = FileUtil.file(ResourceUtils.getURL("") + DateUtil.formatLocalDateTime(LocalDateTime.now()));
} catch (FileNotFoundException e) {
    throw new RuntimeException(e);
}
FileUtil.writeString(sb.toString(), file, Charset.defaultCharset());

恢复操作

@Autowired
private JdbcTemplate jdbcTemplate;

@Test
public void recovery() {
    File file = null;
    String fileName = "";
    try {
        file = FileUtil.file(ResourceUtils.getURL("") + fileName);
    } catch (FileNotFoundException e) {
        throw new RuntimeException(e);
    }
    String s = FileUtil.readString(file, Charset.defaultCharset());
    jdbcTemplate.execute(s);
}