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

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

当然,此方法不适用于海量数据的备份,这只适用于少量数据的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">SELECTcolumn_name,data_typeFROMinformation_schema.COLUMNSWHEREtable_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 {@Autowiredprivate UserService userService;@ResourceMinIoUtil 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_SSDate 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_namepublic static String convertCamelCaseToSnakeCase(String input) {return input.replaceAll("([a-z])([A-Z]+)", "$1_$2").toLowerCase();}}

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

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

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

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

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

相关文章

C++基于Qt中QOpenGLWidget模块实现的画图板源码+可执行文件

基于Qt中QOpenGLWidget模块实现的画图板 一、系统概述 本系统拟完成一个画图板&#xff0c;对多种常见图形进行基本操作系统功能 二维图形的输入&#xff1a;可输入或全部清除直线、矩形、圆、椭圆、多边形、文本等二维图形的变换&#xff1a;在直线、矩形、圆、椭圆、多边形…

【AI视野·今日NLP 自然语言处理论文速览 第四十期】Mon, 25 Sep 2023

AI视野今日CS.NLP 自然语言处理论文速览 Mon, 25 Sep 2023 Totally 46 papers &#x1f449;上期速览✈更多精彩请移步主页 Daily Computation and Language Papers ReConcile: Round-Table Conference Improves Reasoning via Consensus among Diverse LLMs Authors Justin C…

基于微信小程序的民宿短租酒店预订系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言系统主要功能&#xff1a;具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09;有保障的售后福利 代码参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计…

【斯坦福cs324w】中译版 大模型学习笔记九 大模型之Adaptation

文章目录 引言Adaptation的必要性从llm的训练过程分析从下游任务和原始训练任务之间的差异分析 通用的Adaptation配置 当前主流的Adaptation方法ProbingFine-tuningLightweight Fine-tuningPrompt TuningPrefix TuningAdapter Tuning 参考资料 在特定领域的下游任务中&#xff…

使用Python做一个微信机器人

介绍 简介 该程序将微信的内部功能提取出来&#xff0c;然后在程序里加载Python&#xff0c;接着将这些功能导出成库函数&#xff0c;就可以在Python里使用这些函数 程序启动的时候会执行py_code目录下的main.py&#xff0c;类似于你在命令行使用python main.py。 现在会以…

vue + openlayer 按路径移动

示例 创建一个方形的规矩&#xff0c;并让点按轨迹移动。效果如下: 源代码 <template><div><div id"map" class"map"></div><button id"start-animation" ref"startButton">Start Animation</bu…

03 MIT线性代数-矩阵乘法和逆矩阵Multiplication inverse matrices

1. 矩阵乘法 Matrix multiplication 我们通过四种方法讨论如何使矩阵A与B相乘得到矩阵C。其中A为mxn&#xff08;m行n列&#xff09;矩阵&#xff0c;而B为nxp矩阵&#xff0c;则C为mxp矩阵&#xff0c;记cij为矩阵C中第i行第j列的元素 1.1 Regular way 矩阵乘法的标准计算方…

uni-app:canvas-图形实现1

效果 代码 <template><view><!-- 创建了一个宽度为300像素&#xff0c;高度为200像素的canvas元素。canvas-id属性被设置为"firstCanvas"&#xff0c;可以用来在JavaScript中获取该canvas元素的上下文对象。 --><canvas style"width:200p…

【AI视野·今日CV 计算机视觉论文速览 第253期】Mon, 25 Sep 2023

AI视野今日CS.CV 计算机视觉论文速览 Mon, 25 Sep 2023 Totally 64 papers &#x1f449;上期速览✈更多精彩请移步主页 Daily Computer Vision Papers MosaicFusion: Diffusion Models as Data Augmenters for Large Vocabulary Instance Segmentation Authors Jiahao Xie, W…

郁金香2021年游戏辅助技术中级班(一)

郁金香2021年游戏辅助技术中级班&#xff08;一&#xff09; 用代码读取utf8名字字节数组搜索UTF-8字符串 用CE和xdbg分析对象名字从LUA函数的角度进行分析复习怪物名字偏移 用CE和xdbg分析对象数组认识虚函数表分析对象数组 分析对象数组链表部分链表的定义链表的数据在内存里…

想要精通算法和SQL的成长之路 - 最长递增子序列 II(线段树的运用)

想要精通算法和SQL的成长之路 - 最长递增子序列 II&#xff08;线段树的运用&#xff09; 前言一. 最长递增子序列 II1.1 向下递推1.2 向上递推1.3 更新操作1.4 查询操作1.5 完整代码&#xff1a; 前言 想要精通算法和SQL的成长之路 - 系列导航 一. 最长递增子序列 II 原题链接…

OpenAI官方吴达恩《ChatGPT Prompt Engineering 提示词工程师》(2)如何迭代开发提示词

迭代/Iterative 在机器学习中&#xff0c;您经常有一个想法&#xff0c;然后实现它。编写代码&#xff0c;获取数据&#xff0c;训练模型&#xff0c;这就给您一个实验结果。然后您可以查看该输出&#xff0c;进行错误分析&#xff0c;找出哪些地方工作或不工作&#xff0c;然后…

郁金香2021年游戏辅助技术(初级班)(上)

郁金香2021年游戏辅助技术初级班&#xff08;上&#xff09; %p、size_t、%zd、%llu、FindWindow、GetWindowText、SetWindowTextGetWindowThreadProcessId、OpenProcess、ReadProcessMemory封接读内存接口函数 int R4(void* 地址)跨进程向目标进程内存地址写入数值 WriteProce…

【每日一题】递枕头

文章目录 Tag题目来源题目解读解题思路方法一&#xff1a;模拟方法二&#xff1a; O ( 1 ) O(1) O(1) 解法 写在最后 Tag 【模拟】【 O ( 1 ) O(1) O(1) 公式】【2023-09-26】 题目来源 2582. 递枕头 题目解读 编号从 1 到 n 的 n 个人站成一排传递枕头。最初&#xff0c;排…

华南理工大学电子与信息学院23年预推免复试面试经验贴

运气较好&#xff0c;复试分数90.24&#xff0c;电科学硕分数线84、信通83、专硕电子与信息74. 面试流程&#xff1a; 1&#xff1a;5min ppt的介绍。其中前2min用英语简要介绍基本信息&#xff0c;后3min可用英语也可用中文 介绍具体项目信息如大创、科研、竞赛等&#xff08…

出现 conda虚拟环境默认放在C盘 解决方法

目录 1. 问题所示2. 原理分析3. 解决方法3.1 方法一3.2 方法二1. 问题所示 通过conda配置虚拟环境的时候,由于安装在D盘下,但是配置的环境默认都给我放C盘 通过如下命令:conda env list,最后查看该环境的确在C盘下 2. 原理分析 究其根本原因,这是因为默认路径没有足够的…

编程每日一练(多语言实现):判断偶数

文章目录 一、实例描述二、技术要点三、代码实现3.1 C 语言实现3.2 Python 语言实现3.3 Java 语言实现 一、实例描述 利用单条件单分支选择语句判断输入的一个整数 是否是偶数。 运行程序&#xff0c;输入一个 整数18&#xff0c; 然后按回车键&#xff0c;将提示该数字是偶数…

linux使用操作[2]

文章目录 版权声明网络传输ping命令wget命令curl命令端口linux端口端口命令和工具 进程管理查看进程关闭进程 主机状态top命令内容详解磁盘信息监控 版权声明 本博客的内容基于我个人学习黑马程序员课程的学习笔记整理而成。我特此声明&#xff0c;所有版权属于黑马程序员或相…

Android ConstraintLayout app:layout_constraintHorizontal_weight

Android ConstraintLayout app:layout_constraintHorizontal_weight <?xml version"1.0" encoding"utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android"http://schemas.android.com/apk/res/android"xmlns:…

【已解决】qt死活不响应鼠标移动到按钮事件

本博文源于笔者正在研究的内容&#xff0c;这个问题大概捣鼓了一个下午&#xff0c;问题是这样子&#xff1a;我有一个按钮&#xff0c;我应用程序运行时&#xff0c;我鼠标放到按钮上&#xff0c;按钮就会被填充图标。怀揣着这样一个想法&#xff0c;我搜啊搜&#xff0c;整啊…