java或者sh脚本实现 实现 mysql 数据库定时导出并导入(适合linux和windows)

news2024/9/22 9:45:33

定时导出指定数据库的指定表导出到指定数据库

一、Java实现

1、contronller

@Slf4j
@Controller
public class BackupController {
    @Autowired
    BackupService backupService;
    
    //  备份
//    @ResponseBody
//    @PostMapping("/backup/backupByfile")
    @Scheduled(cron="1 * * * * *")
    public void backupByfile() {
        backupService.backupByfile();
    }
}

2、实现类

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.exec.CommandLine;
import org.apache.commons.exec.DefaultExecutor;
import org.apache.commons.exec.ExecuteWatchdog;
import org.apache.commons.exec.PumpStreamHandler;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import vip.xiaonuo.modular.ATest.Backup.service.BackupService;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.nio.file.attribute.BasicFileAttributes;
import java.sql.*;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Slf4j
@Service
public class BackupServiceImpl implements BackupService {
    @Value("${spring.datasource.username}")
    private String username;

    @Value("${spring.datasource.password}")
    private String password;
    // db 源数据库   backupDb  备份数据库
    private String db = "qqq";
    private String backupDb = "aa";
    private String tableName = "user";
    private Duration maxAge = Duration.ofMinutes(3);


    private final Lock lock = new ReentrantLock();
    private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd-HHmmss.SSS");

    /**
     * 2、备份到指定文件夹
     */
    // 备份目录
    private String dir = "D:\\backups";

    @Override
    public void backupByfile() {
        File directory = new File(dir);

        if (directory.exists() && directory.isDirectory()) {
            File[] files = directory.listFiles();
            if (files != null) {
                for (File file : files) {
                    if (file.delete()) {
                        log.info("File '{}' deleted successfully.", file.getName());
                    }
                }
            }
        }
        if (!this.lock.tryLock()) {
            throw new RuntimeException("备份任务进行中!");
        }

        try {

             String now = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
            Path dir = Paths.get(this.dir);

            // 备份的SQL文件
            Path sqlFile = dir.resolve(Paths.get(now + ".sql"));

            if (Files.exists(sqlFile)) {
                // 文件已经存在,则添加后缀
                for (int i = 1; i >= 1; i++) {
                    sqlFile = dir.resolve(Paths.get(now + "-" + i + ".sql"));
                    if (!Files.exists(sqlFile)) {
                        break;
                    }
                }
            }
            // 初始化目录
            if (!Files.isDirectory(sqlFile.getParent())) {
                Files.createDirectories(sqlFile.getParent());
            }

            // 创建备份文件文件
            Files.createFile(sqlFile);

            // 标准流输出的内容就是 SQL 的备份内容
            try (OutputStream stdOut = new BufferedOutputStream(
                    Files.newOutputStream(sqlFile, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING))) {

                // 监视狗。执行超时时间,1小时
                ExecuteWatchdog watchdog = new ExecuteWatchdog(TimeUnit.HOURS.toMillis(1));

                // 子进程执行器
                DefaultExecutor defaultExecutor = new DefaultExecutor();
                // defaultExecutor.setWorkingDirectory(null); // 工作目录
                defaultExecutor.setWatchdog(watchdog);
                defaultExecutor.setStreamHandler(new PumpStreamHandler(stdOut, System.err));

                // 进程执行命令
                CommandLine commandLine = new CommandLine("mysqldump");
                commandLine.addArgument("-u" + this.username);    // User name
                commandLine.addArgument("-p" + this.password);    // Password
                commandLine.addArgument(this.db);                // Database name
                commandLine.addArgument(this.tableName);               // Table name

                log.info("备份 SQL 数据");

                // 同步执行,阻塞直到子进程执行完毕。
                int exitCode = defaultExecutor.execute(commandLine);

                if (defaultExecutor.isFailure(exitCode)) {
                    throw new RuntimeException("备份任务执行异常:exitCode=" + exitCode);
                }
            }
            // 替换备份文件中的表名
            replaceTableName(sqlFile, this.tableName, this.tableName + "_" + now);
            // 导入 SQL 文件
            String path = sqlFile.toAbsolutePath().toString();
            importSql(path);

        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            this.lock.unlock();
        }
    }


    private void replaceTableName(Path sqlFile, String oldTableName, String newTableName) throws IOException {
        List<String> lines = Files.readAllLines(sqlFile, StandardCharsets.UTF_8);
        for (int i = 0; i < lines.size(); i++) {
            String line = lines.get(i);
            if (line.contains(oldTableName)) {
                lines.set(i, line.replace(oldTableName, newTableName));
            }
        }
        Files.write(sqlFile, lines, StandardCharsets.UTF_8);
    }

    public void importSql(String fPath) {
        try {
            Runtime rt = Runtime.getRuntime();
            Process child = rt.exec("mysql -u" + this.username + " -p" + this.password + " " + this.backupDb);
            OutputStream out = child.getOutputStream();
            String inStr;
            StringBuilder  sb = new StringBuilder ("");
            String outStr;
            BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(fPath), "utf8"));

            while ((inStr = br.readLine()) != null) {
                sb.append(inStr + "\r\n");
            }
            outStr = sb.toString();

            try (OutputStreamWriter writer = new OutputStreamWriter(out, "utf8")) {
                writer.write(outStr);
                writer.flush();
            }

            int exitCode = child.waitFor();
            if (exitCode != 0) {
                throw new RuntimeException("导入 SQL 文件失败,退出码: " + exitCode);
            }
            log.info("导入 SQL 文件成功!");

        } catch (Exception e) {
            throw new RuntimeException("出错了," + e);
        }
    }
}

3、执行结果二、sh脚本实现

1、新建一个.bash脚本

#!/bin/bash

# 源数据库配置
SOURCE_DB="qhd"
SOURCE_HOST="localhost"  # 或者改为实际的 IP 地址
SOURCE_PORT="13306"
SOURCE_USER="root"
SOURCE_PASS="123456"

# 目标数据库配置
TARGET_DB="aa"
TARGET_HOST="localhost"  # 或者改为实际的 IP 地址
TARGET_PORT="13306"
TARGET_USER="root"
TARGET_PASS="123456"

# 要导出的表
SOURCE_TABLE="owner"
CURRENT_DATETIME=$(date +"%Y%m%d%H%M%S")
EXPORT_TABLE_NAME="${SOURCE_TABLE}_${CURRENT_DATETIME}"

# 导出 SQL 文件的路径
EXPORT_DIR="/home/mengqingda/program/test/file"
EXPORT_FILE="$EXPORT_DIR/${EXPORT_TABLE_NAME}.sql"

# 创建导出目录(如果不存在)
mkdir -p "$EXPORT_DIR"

echo "开始导出 $EXPORT_TABLE_NAME 表数据..."

# 导出指定表的数据
mysqldump -h$SOURCE_HOST -P$SOURCE_PORT -u$SOURCE_USER -p$SOURCE_PASS $SOURCE_DB $SOURCE_TABLE > $EXPORT_FILE

if [ $? -eq 0 ]; then
    echo "数据导出完成, 开始导入 $EXPORT_TABLE_NAME 表数据到 $TARGET_DB 数据库..."

    # 导入数据到目标数据库
    mysql -h$TARGET_HOST -P$TARGET_PORT -u$TARGET_USER -p$TARGET_PASS $TARGET_DB -e "CREATE TABLE $EXPORT_TABLE_NAME LIKE $SOURCE_DB.$SOURCE_TABLE; INSERT INTO $EXPORT_TABLE_NAME SELECT * FROM $SOURCE_DB.$SOURCE_TABLE;"

    if [ $? -eq 0 ]; then
        echo "数据导入完成!"
    else
        echo "数据导入失败!"
    fi
else
    echo "数据导出失败!"
fi

2、在linux打开定时任务执行脚本(因为定时只有linux 可以执行)

(1)、先赋予文件夹权限
chmod -R 777 /home/mengqingda/program/test
(2)、然后执行
crontab -e

(3)、如果不习惯用这个编译器可以切换vim编译器进行编辑

export EDITOR="/usr/bin/vim" ; 

 (4)、添加定时任务(5分钟一次)

*/5 * * * * /home/mengqingda/program/test/backup.sh

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

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

相关文章

CANopen 控制多台设备的支持能力与定制方案评估

1. CANopen 支持的设备数量 CAN 总线的物理限制&#xff1a;CANopen 基于 CAN 总线协议&#xff0c;其设备数量受到 CAN 总线物理层的限制。标准 CAN 总线通常支持最多 127 个节点&#xff0c;但实际应用中&#xff0c;考虑到总线负载、波特率、线缆长度、网络拓扑等因素&#…

(Java)集合框架

1.集合的简介 集合Collection&#xff0c;也是一个数据容器&#xff0c;类似于数组&#xff0c;但是和数组是不一样的。集合是一个可变的容器&#xff0c;可以随时向集合中添加元素&#xff0c;也可以随时从集合中删除元素。另外&#xff0c;集合还提供了若干个用来操作集合中…

[upload]-[GXYCTF2019]BabyUpload1-笔记

尝试上传.htaccess和图片和一句话木马提示 php文件提示 响应头可以看到 构造一句话图片木马如下&#xff1a; <script languagephp>eval($_POST[cmd]);</script> 上传成功 必须增加文件夹下jpg后缀解析php .htaccess如下 <FilesMatch "jpg">Set…

windows关闭英语美式键盘

命令窗口 在Windows 中&#xff0c;如果你可通过批处理文件&#xff08;.bat&#xff09;关闭或移除美式键盘布局&#xff0c;可以使用以下步骤创建一个简单的批处理脚本&#xff1a; 打开windows命令窗口 执行命令 reg add "HKCU\Keyboard Layout\Toggle" /v &quo…

多模态感知:打造温室作物的全方位“健康档案“

&#xff08; 于景鑫 国家农业信息化工程技术研究中心&#xff09;现代农业的发展&#xff0c;离不开现代科技的支撑。在温室种植领域&#xff0c;由于环境复杂多变、管理要素繁多&#xff0c;传统人工经验难以应对日益精细化、智能化的生产需求。多模态感知技术的出现&#xf…

由于Offer报文引起的事件订阅失败

今天在工作中碰到一个车机上someip事件订阅的问题&#xff0c;Android端订阅了S32G发布的定位相关的someip服务(0x0001)中的某个事件&#xff08;卫星状态&#xff09;&#xff0c;然后这个事件是基于TCP通信的&#xff0c;设置了通信端口50001。 然后Android端上层应用反馈说收…

机器学习课程学习周报七

机器学习课程学习周报七 文章目录 机器学习课程学习周报七摘要Abstract一、机器学习部分1.1 Transformer模型概述1.2 Transformer编码器1.3 Transformer解码器1.3.1 自回归解码器1.3.2 非自回归解码器 1.4 编码器-解码器注意力1.5 Transformer的训练过程 总结 摘要 本周的学习…

How to debug a appliction on local Linux or WSL?

由于K8S权限控制&#xff0c;当部署在上面的应用程式出现问题后&#xff0c;无法还原用户出问题的场景。所以需要把程式部署到本地的Linux或WSL。 1.Upload application publish files to your Linux or WSL. 2.Add a Dockerfile FROM harbor.xxx.com/dotnet/aspnet:6.0 MAIN…

SQL注入之二次,加解密,DNS注入

加解密注入 在注入的时候&#xff0c;对变量做了加密操作&#xff0c;比如说?id1正常显示&#xff0c;但是代码对1进行了加密&#xff0c;这个时候想用?id1 and 11去判断&#xff0c;就得把1 and 11整体按照网站的方式加密&#xff0c;再去注入 二次注入 无法通过手动注入…

idea和jdk的安装教程

1.JDK的安装 下载 进入官网&#xff0c;找到你需要的JDK版本 Java Downloads | Oracle 中国 我这里是windows的jdk17&#xff0c;选择以下 安装 点击下一步&#xff0c;安装完成 配置环境变量 打开查看高级系统设置 在系统变量中添加两个配置 一个变量名是 JAVA_HOME …

人工智能与机器学习原理精解【12】

文章目录 分级聚类理论分级聚类的详细说明1. 定义2. 算法3. 计算4. 例子5. 例题 皮尔逊相关系数 julia实现 参考文献 分级聚类 理论 分级聚类的详细说明 1. 定义 分级聚类&#xff08;Hierarchical Clustering&#xff09;&#xff0c;又称为层次聚类&#xff0c;是一种通过…

Java虚拟机:虚拟机介绍

大家好&#xff0c;我是栗筝i&#xff0c;这篇文章是我的 “栗筝i 的 Java 技术栈” 专栏的第 033 篇文章&#xff0c;在 “栗筝i 的 Java 技术栈” 这个专栏中我会持续为大家更新 Java 技术相关全套技术栈内容。专栏的主要目标是已经有一定 Java 开发经验&#xff0c;并希望进…

haproxy 原理+实战

haproxy 1 haproxy简介1.1 定义1.2 原理讲解1.3 HAProxy的优点&#xff1a; 2. haproxy的基本部署2.1 实验环境2.1.2 haproxy主机配置2.1.3 webserver1配置2.1.4 webserver2配置 3. haproxy的全局配置4. haproxy代理参数5. haporxy的热处理6.haproxy的算法6.1 静态算法6.1.1sta…

物联网HMI/网关搭载ARM+CODESYS实现软PLC+HMI一体化

物联网HMI/网关搭载CODESYS实现软PLCHMI一体化 硬件&#xff1a;ARM平台&#xff0c;支持STM32/全志T3/RK3568/树莓派等平台 软件&#xff1a;CODESYS V3.5、JMobile Studio CODESYS是一款功能强大的PLC软件编程工具&#xff0c;它支持IEC61131-3标准IL、ST、FBD、LD、CFC、…

数据结构之《二叉树》(下)

在二叉树(中)了解了堆的相关概念后还实现了堆&#xff0c;并且还实现了堆排序&#xff0c;以及解决了TOP-K问题。接下来在本篇中将继续学习二叉树中的链式结构&#xff0c;会学习二叉树中的前、中、后三种遍历并实现链式结构的二叉树&#xff0c;接下来就开始本篇的学习吧&…

LabVIEW开发多语言程序的实现

在全球化的背景下&#xff0c;软件开发中的多语言支持变得愈发重要。LabVIEW作为一种广泛应用于工程和科学领域的图形化编程语言&#xff0c;同样支持多语言应用的开发。实现一个多语言LabVIEW程序不仅能增强用户体验&#xff0c;还可以扩大应用的覆盖范围。本文将介绍在LabVIE…

算法复习(上)

数组复习 数组复习基本就是熟练使用数组&#xff0c;经常配合指针使用以及思维的使用 443. 压缩字符串 - 力扣&#xff08;LeetCode&#xff09; 使用双指针分别标志我们在字符串中读和写的位置&#xff0c;当读指针 read 位于字符串的末尾&#xff0c;或读指针 read 指向的…

Python3 第八十一课 -- urllib

目录 一. 前言 二. urllib.request 三. urllib.error 四. urllib.parse 五. urllib.robotparser 一. 前言 Python urllib 库用于操作网页 URL&#xff0c;并对网页的内容进行抓取处理。 本文主要介绍 Python3 的 urllib。 urllib 包 包含以下几个模块&#xff1a; url…

C# 利用自定义特性,动态拼接sql,查询数据库,动态新增datagridview 列

之前在给一个工厂客户开发一套“售后包装防错系统”的时候&#xff0c;由于业务比较复杂&#xff0c; 每个表的字段基本都保持在10-20个字段区间&#xff0c;如下截图&#xff08;可向右滑动滚动条&#xff09; 正常的做法&#xff0c;肯定是一顿卡卡操作&#xff0c;新建列&…

Java——反射(1/4):认识反射(反射(Reflection)、反射学什么 )、获取类(获取Class对象的三种方式、代码演示)

目录 认识反射 反射&#xff08;Reflection&#xff09; 反射学什么 获取类 获取Class对象的三种方式 代码演示 认识反射 反射&#xff08;Reflection&#xff09; 反射就是&#xff1a;加载类&#xff0c;并允许以编程的方式解剖类中的各种成分&#xff08;成员变量、…