数据备份文件生成--根据表名生成对应的sql语句文件

news2025/1/1 23:55:23

最近客户有个需求,希望在后台增加手动备份功能,将数据导出下载保存。

当然,此方法不适用于海量数据的备份,这只适用于少量数据的sql备份。

这是我生成的sql文件,以及sql文件里的insert语句,已亲测,可以直接执行:

项目是SSM框架,接下来就展示我的实现代码:

首先是接受字段的实体类:

@Data
public class ColumnsDto {

    /**
     * 表结构的主要字段*
     */
    private String column_name;
    //该字段则是表字段的数据类型  暂时不需要
    private String data_type;

}

然后是用的到两个主要的sql:

1.此sql用于查询表的有效字段信息(table_schema:当前的数据库名

  <select id="queryColumnsByTableName" resultType="com.hle.monitor.entity.vo.ColumnsDto">
    SELECT
      column_name,
      data_type
    FROM
      information_schema.COLUMNS
    WHERE
      table_name = #{tableName}
      AND table_schema = 'supervision_data'
    ORDER BY ordinal_position
  </select>

2.再用sql查询表的所有数据:(注意:此处表名需要要用$而不是#号)

  <select id="findBackupAll"  resultType="java.util.Map">
    select * from ${tableName}
  </select>

此处我省略了相应的service和mapper文件内容,直接展示最重要的controller代码:


import com.hle.monitor.entity.Results;
import com.hle.monitor.entity.vo.ColumnsDto;
import com.hle.monitor.service.UserService;
import com.hle.monitor.util.DateUtils;
import com.hle.monitor.util.MinIoUtil;
import com.hle.monitor.util.ParameterUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.http.entity.ContentType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.*;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;


/**
 * @author
 */
@CrossOrigin(origins = "*")
@RestController()
@RequestMapping("/backup")
@Api(tags = "备份相关接口类")
@Scope("prototype")
public class BackupController {

    @Autowired
    private UserService userService;

    @Resource
    MinIoUtil minIoUtil;

    //本地文件夹路径
    private static String backupFilePath = "./sql/";

    @ApiOperation(value = "根据表名备份信息")
    @GetMapping("/{tableName}")
    public Results backupTable(@PathVariable("tableName") String tableName) {
        //表有效字段信息
        List<ColumnsDto> columnsDtoList = userService.queryColumnsByTableName(tableName);
        if(columnsDtoList.isEmpty()) return new Results(500, "该表无有效字段信息!");
        //文件名--先在本地创建写入后再进行删除
        String fileName =  System.currentTimeMillis() + "-" + tableName + ".sql";
        try {
            //获取所有备份数据
            List<Map<String, Object>> records = userService.findBackupAll(tableName);

            String path = backupFilePath + fileName;
            //不存在文件夹则创建
            File directory = new File(backupFilePath);
            directory.mkdirs();
            BufferedWriter writer = new BufferedWriter(new FileWriter(path));
            for (Map record : records) {
                String insertStatement = generateInsertStatement(tableName, record, columnsDtoList) + ";";
                writer.write(insertStatement);
                writer.newLine();
            }
            writer.close();
            File file = new File(path);
            InputStream inputStream = new FileInputStream(file);
            MultipartFile multipartFile = new MockMultipartFile(ContentType.APPLICATION_OCTET_STREAM.toString(), inputStream);
            minIoUtil.upload(multipartFile, ParameterUtil.bucketNameParam, fileName);

            //上传后 删除本地文件
            file.delete();
            System.out.println("Backup created successfully!");
        } catch (IOException e) {
            e.printStackTrace();
            return new Results(500, "操作失败!");
        }
        return new Results(200, "操作成功!", fileName);
    }


    //此方法需要以数据库取出来的字段信息为准--转换成sql的方法
    private String generateInsertStatement(String tableName, Map<String, Object> record, List<ColumnsDto> columnsDtoList) {
        StringBuilder builder = new StringBuilder();
        builder.append("INSERT INTO ").append(tableName).append(" (");
        //拼接列名
        columnsDtoList.forEach(columns -> {
            builder.append(columns.getColumn_name()).append(", ");
        });
        builder.setLength(builder.length() - 2);
        builder.append(") VALUES (");
        //拼接值
        columnsDtoList.forEach(columns -> {
            Object value = record.get(columns.getColumn_name());
            if(value instanceof Date){
                Date date = (Date) value;
                builder.append("'").append(DateUtils.parseDateToStr(date)).append("', ");
            }
            else if(value instanceof String){
                builder.append("'").append(value).append("', ");
            }else{
                builder.append(value).append(", ");
            }
        });
        builder.setLength(builder.length() - 2);
        builder.append(")");
        return builder.toString();
    }


    //此方法用于直接取Object的字段信息做sql拼接--转换成sql的方法--已验证过
    private String generateInsertStatement(String tableName, Object record) {
        StringBuilder builder = new StringBuilder();
        builder.append("INSERT INTO ").append(tableName).append(" (");
        Arrays.stream(record.getClass().getDeclaredFields())
                .map(Field::getName)
                .forEach(fieldName -> builder.append(convertCamelCaseToSnakeCase(fieldName)).append(", "));
        builder.setLength(builder.length() - 2);
        builder.append(") VALUES (");
        Arrays.stream(record.getClass().getDeclaredFields())
                .map(field -> {
                    field.setAccessible(true);
                    try {
                        return field.get(record);
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                        return null;
                    }
                })
                .forEach(value -> {
                    if(value instanceof Date){
                        //时间格式 转换为-YYYY_MM_DD_HH_MM_SS
                        Date date = (Date) value;
                        builder.append("'").append(DateUtils.parseDateToStr(date)).append("', ");
                    }
                    else if(value instanceof String){
                        builder.append("'").append(value).append("', ");
                    }else{
                        //int/double类型 不需要单引号
                        builder.append(value).append(", ");
                    }
                });

        builder.setLength(builder.length() - 2);
        builder.append(")");
        return builder.toString();
    }

    //驼峰命令转换 userName-转换为-user_name
    public static String convertCamelCaseToSnakeCase(String input) {
        return input.replaceAll("([a-z])([A-Z]+)", "$1_$2").toLowerCase();
    }


}

在controller中提供了两种方法,可以参考一下~,然后直接调用接口就行:

因为项目需要,我是写入文件后再上传至minio文件服务器,所以我要查看还需要去minio服务器查看下载,或者调用现有的下载接口下载~

这样就完成了根据sql文件数据备份~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1033871.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Software Grand Exposure: SGX Cache Attacks Are Practical【WOOT‘17】

目录 摘要引言我们的目标和贡献贡献新颖的SGX缓存攻击技术非加密应用程序泄漏对策分析 背景Intel SGX缓存结构性能监视计数器 系统和威胁模型对手的能力进攻目标 攻击设计PrimeProbePrimeProbe for SGX挑战 作者&#xff1a;Ferdinand Brasser, Urs M ̈uller, Alexandra Dmitr…

2023 第十二届中国智能产业高峰论坛 - 文档大模型的未来展望

目录 前言文档图像分析识别与理解中的技术挑战 文档图像分析识别与理解的研究主题文档图像分析与预处理文档解析与识别版面分析与还原文档信息抽取与理解AI安全知识化&存储检索和管理 多模态大模型在文档图像处理中的应用多模态的GPT-4在文档图像上的表现多模态的Google Ba…

Spring Security :二【原理解析、会话管理、RBAC中集成认证和授权、JWT】

文章目录 三、原理解析3.1 结构分析3.1 登录认证流程分析3.1.1 **UserDetailsService**3.1.2 自定义UserDetailsService3.1.3 **PasswordEncoder** 3.2 授权流程分析3.2.1 配置方式的原理解析3.2.2 注解方式原理解析 四、会话管理4.1 获取用户身份4.2 会话控制 五、 RBAC中集成…

swoole开发功能的消息队列与异步通信实现原理

随着互联网技术的迅猛发展&#xff0c;开发者对于高性能和高并发的需求也变得越来越迫切。作为一款开发框架&#xff0c;Swoole因其卓越的性能和丰富的功能而受到越来越多开发者的青睐。本文将介绍Swoole中消息队列和异步通信的实现原理&#xff0c;并结合代码示例进行详细说明…

远程桌面软件是否支持远程访问远程网络监控系统

远程桌面软件是一种通过网络连接&#xff0c;实现远程访问和控制计算机桌面的工具。它允许用户在自己的设备上操作远程计算机&#xff0c;就像直接坐在那台计算机前一样。然而&#xff0c;这种软件能否支持远程访问远程网络监控系统&#xff0c;取决于具体的软件以及目标网络监…

在React中,什么是组件的生命周期?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 挂载阶段&#xff08;Mounting&#xff09;⭐ 更新阶段&#xff08;Updating&#xff09;⭐ 卸载阶段&#xff08;Unmounting&#xff09;⭐ 错误处理阶段&#xff08;Error Handling&#xff09;⭐ 新的生命周期方法⭐ 写在最后 ⭐ 专栏…

初识Java 10-2 集合

目录 LinkedList Stack Queue Set Map 新特性&#xff1a;记录&#xff08;record&#xff09;类型 本笔记参考自&#xff1a; 《On Java 中文版》 LinkedList LinkedList同样实现了基本的List接口。相比于ArrayList&#xff0c;LinkedList拥有更快的插入和删除效率&…

华为云云耀云服务器L实例评测|Docker版的Minio安装 Springboot项目中的使用 结合vue进行图片的存取

前言 最近华为云云耀云服务器L实例上新&#xff0c;也搞了一台来玩&#xff0c;期间遇到过MySQL数据库被攻击的情况&#xff0c;Redis被攻击的情况&#xff0c;教训是密码不能太简单。在使用服务器时&#xff0c;学习到很多运维相关的知识。 本篇博客介绍如何在Linux中安装mi…

【数据结构】—交换排序之快速排序究极详解,手把手带你从简单的冒泡排序升级到排序的难点{快速排序}(含C语言实现)

食用指南&#xff1a;本文在有C基础的情况下食用更佳 &#x1f525;这就不得不推荐此专栏了&#xff1a;C语言 ♈️今日夜电波&#xff1a;靴の花火—ヨルシカ 0:28━━━━━━️&#x1f49f;──────── 5:03 …

搜款网VVIC根据ID取商品详情 API 关键词搜索商品列表

搜款网是一家服装批发平台&#xff0c;提供多个品牌和供应商的服装、鞋子、箱包等商品供采购者选择&#xff0c;为了获取商品详情&#xff0c;您需要使用搜款网的API接口。 建议您联系搜款网的客服或开发者&#xff0c;以获取更多关于API接口的信息&#xff0c;包括使用方法、…

5+氧化应激+预后模型

今天给同学们分享一篇氧化应激预后模型的生信文章“A four oxidative stress gene prognostic model and integrated immunity-analysis in pancreatic adenocarcinoma”&#xff0c;这篇文章于2023年1月13日发表在Front Oncol期刊上&#xff0c;影响因子为5.738。 胰腺腺癌&am…

macOS Sonoma 14 RC2(23A344)/Ventura13.6/Monterey 12.7 三版系统同时更新

macOS Sonoma 14 RC2&#xff08;23A344&#xff09;/macOS13.6/macOS 12.7 同时更新

[论文阅读]YOLOV1:You Only Look Once:Unified, Real-Time Object Detection

摘要 我们提出了YOLO&#xff0c;一种新的目标检测方法。之前的目标检测工作重新使用分类器来执行检测。相反&#xff0c;我们将目标检测表述为空间分离的边界框和相关类概率的回归问题。单个神经网络在一次评估中直接从完整图像中预测边界框和类别概率。由于整个检测管道是一…

reduce the indexing time and cpu load with pre-build jdk shared indexes

在idea2022.3.3版本中打开项目 遇到问题 提示&#xff1a; Idea突然不停indexing reduce the indexing time and cpu load with pre-build jdk shared indexes解决方法 找到设置&#xff0c;设置成如图效果&#xff1a; 然后再找到如图位置&#xff1a; 勾选清理&#xff…

Android Version、MinSDK(API)和https的对应关系

这边主要是对Android开发过程中的各个版本对应的API Levl做个总结&#xff0c;同时分析一下Https在哪个Android版本上面做强制要求。对于Android的开发也有一定的帮助。

瑞云科技联合华为云推出云渲染AI加速模式,助力CG行业渲染效率再升级

如今&#xff0c;无论是在工业设计、建筑设计等设计行业&#xff0c;还是在影视、动画等娱乐行业&#xff0c;越来越多企业开始将目光转向云技术&#xff0c;以提升数字内容生产效率。而在数字内容制作过程中&#xff0c;渲染起着至关重要的作用&#xff0c;因此&#xff0c;提…

Qt测量屏幕的分辨率

Qt 入门实战教程&#xff08;目录&#xff09; 什么是屏幕分辨率 我们手机&#xff0c;平板&#xff0c;个人台式机显示器&#xff0c;笔记本显示器家里的液晶电视显示器在显示画面的时候&#xff0c;都是由一个一个的像素点组成的。 不同的像素点显示不同的颜色&#xff0c…

Windows和VMware中的Ubuntu互传文件

1、方法一&#xff1a;创建共享文件夹 1.1、创建环境 (1)VMware: V17.0.0 (2)Ununtu: Ubuntu 22.04.3 LTS (3)Windows: Windows10 (4)需要在Ubuntu开机状态下进行配置。 1.2、创建步骤 (1)打开VMware&#xff0c;依次点击“虚拟机”→“设置”。 (2)依次点击“选项”→“…

使用transformers进行端到端的目标检测

目录 目标检测的旧方法 使用transformers进行端到端的目标检测 抛去了目标检测旧的方法 网络架构 Transformer encoder Transformers and Parallel Decoding 注意力起到的作用 使用Hungarian algorithm算法完成匹配 在使用transformers的端到端目标检测中&#xff0c;匈…

正确理解redux Toolkits中createSlice的action.payload

使用redux Toolkits中的createSlice编写extraReducers经常看到使用action.payload来更新state状态值&#xff1a; 那么action.payload指的到底是什么&#xff1f; 让我们看看action的定义部分&#xff1a; 注意&#xff1a; action.payload不是上面ajax请求的返回内容&#x…