java或者sh脚本实现 实现 mysql 数据库指定表,定时导出并导入指定数据库并切换指定字段名(适合linux和windows)

news2024/9/23 9:31:38

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

一、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-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

1-2、新建一个.bash脚本(切换指定字段名)

#!/bin/bash

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

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

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

# 导出 SQL 文件的路径
EXPORT_DIR="D:\ProgramFiles\programSoftware\backups"
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 "数据导出完成, 开始修改 SQL 文件..."

    echo "SQL 文件修改完成, 开始创建目标表..."

    # 创建目标表
    mysql -h$TARGET_HOST -P$TARGET_PORT -u$TARGET_USER -p$TARGET_PASS $TARGET_DB -e "
    CREATE TABLE IF NOT EXISTS $EXPORT_TABLE_NAME LIKE $SOURCE_DB.$SOURCE_TABLE;
    ALTER TABLE $EXPORT_TABLE_NAME 
        CHANGE xm 姓名 VARCHAR(255),
        CHANGE bj 班级 VARCHAR(255),
        CHANGE xh 学号 VARCHAR(255),
        CHANGE wx 微信 VARCHAR(255),
        CHANGE qq qq号 VARCHAR(255),
        CHANGE zw 职位 VARCHAR(255),
        CHANGE xl 学历 VARCHAR(255);
"
    echo "目标表创建完成, 开始导入数据..."

    # 导入数据到目标表
    mysql -h$TARGET_HOST -P$TARGET_PORT -u$TARGET_USER -p$TARGET_PASS $TARGET_DB -e "
    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/2038802.html

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

相关文章

音视频开发

通过多线程分别获取高分辨率(1920 * 1080)和低分辨率(1280 * 720) 初始化VI模块 初始化HIGH VENC模块 初始化LOW VENC模块 初始化RGA模块 绑定 VI和HIGH VENC 绑定 VI和RGA 创建线程 HIGH VENC处理 RGA处理 LOW VENC处理 销毁 QP原理的讲解 QP参数调节&#xff0c;指的是量化…

C:每日一题:二分查找

1、知识介绍&#xff1a; 1.1 概念&#xff1a; 二分查找是一种在有序数组中查找某一特定元素的搜索算法 1.2 基本思想&#xff1a; 每次将待查找的范围缩小一半&#xff0c;通过比较中间元素与目标元素的大小&#xff0c;来决定是在左半部分还是右半部分继续查找。 举个生…

进程状态和线程

一、wait&#xff08;阻塞调用&#xff09; pid_t wait(int *status); 1.功能&#xff1a;&#xff08;1&#xff09;获取子进程退出状态 &#xff08;2&#xff09;.回收资源 //会让僵尸态的子进程销毁 参数 int *status: 指向一个整数的指针&#xff0c;wait …

qtday01

实现一个登录窗口 #include "mywidget.h"MyWidget::MyWidget(QWidget *parent): QWidget(parent) {//设置标题this->setWindowTitle("小黑子登录器");//设置图标this->setWindowIcon(QIcon("E:\\qt\\day1_04\\pictrue\\cxk.gif"));//固定…

移动APP测试有哪些注意事项?专业APP测试报告如何获取?

移动APP在其生命周期中有不同的阶段&#xff0c;从开始到投入目标市场再到被淘汰。移动APP的成功有多种因素&#xff0c;例如创建、部署、推广、粘性等。但是&#xff0c;创建出色APP的关键在于它的测试&#xff0c;软件测试负责为客户提供安全有效的产品&#xff0c;因此移动A…

Haproxy实现https

haproxy可以实现https的证书安全,从用户到haproxy为https,从haproxy到后端服务器用http通信 &#xff0c;但是基于性能考虑,生产中证书都是在后端服务器比如nginx上实现。 配置HAProxy支持https协议&#xff0c;支持ssl会话&#xff1a; bind *:443 ssl crt /PATH/TO/SOME_PEM…

【C++ 面试 - 基础题】每日 3 题(十)

✍个人博客&#xff1a;Pandaconda-CSDN博客 &#x1f4e3;专栏地址&#xff1a;http://t.csdnimg.cn/fYaBd &#x1f4da;专栏简介&#xff1a;在这个专栏中&#xff0c;我将会分享 C 面试中常见的面试题给大家~ ❤️如果有收获的话&#xff0c;欢迎点赞&#x1f44d;收藏&…

如何把命令行创建python虚拟环境与pycharm项目管理更好地结合起来

1. 问题的提出 我在linux或windows下的某个目录如“X”下使用命令行的方式创建了一个python虚拟环境&#xff08;参考文章&#xff09;&#xff0c;对应的目录为myvenv, 现在我想使用pycharm创建python项目myproject&#xff0c;并且利用虚拟环境myvenv&#xff0c;怎么办&…

搭建jenkins+k8s过程中遇到的问题

1、k8s地址配置导致的一些个问题 Still waiting to schedule task ‘Jenkins’ doesn’t have label ‘k8s-jenkins-slave’ 出现以上异常一般就是k8s地址配置不对或者地址不通导致的 配置完k8s地址以及命名空间等内容之后,在获取k8s下的token 1.查看sa # kubectl get sa…

我的第一个CUDA程序

MatAdd算法 实现两个矩阵对应元素相加 MatAdd算法的GPU实现 CPU端为输入矩阵A和B、输出矩阵C分配空间&#xff0c;并进行初始化CPU端分配设备端内存&#xff0c;并将A和B传输到GPU上定义数据和线程的映射关系&#xff0c;并确定线程的开启数量和组织方式 每个线程负责输出矩阵…

EasyX自学笔记3(割草游戏1)

割草游戏&#xff0c;有玩家&#xff08;上下左右控制移动&#xff09;周围围绕子弹&#xff0c;敌人&#xff08;随机刷新&#xff09;向玩家靠近&#xff0c;子弹打死敌人&#xff0c;玩家与敌人触碰游戏结束。 分析需求 1.有玩家、敌人、子弹三种对象 2.玩家上下左右控制…

Spring MVC数据绑定和响应学习笔记

学习视频:12001 数据绑定_哔哩哔哩_bilibili 目录 1.数据绑定 简单数据绑定 默认类型数据绑定 简单数据类型绑定的概念 参数别名的设置 PathVariable注解的两个常用属性 POJO绑定 自定义类型转换器 xml方式 注解方式 数组绑定 集合绑定 复杂POJO绑定 属性为对象类…

力扣面试经典算法150题:最长公共前缀

最长公共前缀 今天的题目是力扣面试经典150题中的数组的简单题: 最长公共前缀 题目链接&#xff1a;https://leetcode.cn/problems/longest-common-prefix/description/?envTypestudy-plan-v2&envIdtop-interview-150 题目描述 编写一个函数来查找字符串数组中的最长公…

修改OpenSSH服务版本号

前言 这几年信息安全要求很高&#xff0c;奈何口号响亮掩盖不了我们技术基础依然很低的事实&#xff0c;加上风口烧钱和政绩工程等因素&#xff0c;于是就诞生了一些乱象&#xff0c;其中一个就是安全扫描胡乱标记&#xff0c;这里面的典型就是OpenSSH的漏洞扫描报告。 比如&…

人工智能小车——智能车臂控制平台

随着机器人技术的不断发展 &#xff0c;各行业对机器人应用人才的需求也随之增加&#xff0c;培养符合行业发展需求的机器人技术专业人才成为了高校的重要任务。 基本介绍 智能车臂控制平台&#xff08;ZI-AutoRB&#xff09;是一套用以机器人控制技术学习和研究的软硬件系统。…

米联客-FPGA程序设计Verilog语法入门篇连载-10 Verilog语法_一般设计规范

软件版本&#xff1a;无 操作系统&#xff1a;WIN10 64bit 硬件平台&#xff1a;适用所有系列FPGA 板卡获取平台&#xff1a;https://milianke.tmall.com/ 登录“米联客”FPGA社区 http://www.uisrc.com 视频课程、答疑解惑&#xff01; 1概述 本小节讲解Verilog语法的一般…

照片回收利器:最新数据恢复软件推荐

照片回收利器&#xff1a;最新数据恢复软件推荐 在今天的数字化时代&#xff0c;我们将大量珍贵的照片和个人数据存储在电脑、手机和其他设备中。然而&#xff0c;由于各种原因&#xff0c;这些数据可能会意外删除或丢失&#xff0c;这对我们来说是一个巨大的损失。因此&#…

【Redis】List类型

目录 List列表 命令 LPUSH LPUSHX RPUSH RPUSHX LRANGE LPOP RPOP LINDEX LINSERT LLEN lrem ltrim lset 阻塞版本命令 BLPOP BRPOP 内部编码 使用场景 消息队列 分频道的消息队列 作为栈或者队列 List列表 列表类型是⽤来存储多个有序的字符串&…

5 大场景上手通义灵码企业知识库 RAG

大家好&#xff0c;我是通义灵码&#xff0c;你的智能编程助手&#xff01;最近我又升级啦&#xff0c;智能问答功能全面升级至 Qwen2&#xff0c;新版本在各个方面的性能和准确性都得到了显著提升。此外&#xff0c;行间代码补全效果也全面优化&#xff0c;多种编程语言生成性…

python-小理和他的猫(赛氪OJ)

[题目描述] 今天小理又要为他的猫小咪准备好吃的猫粮了&#xff0c;你愿意帮助一下他们么&#xff1f; 小理现在拥有的金钱数为 N &#xff0c;有 M 种小咪喜欢的猫粮从左到右排列&#xff0c;已知每种猫粮的价格 ai​ &#xff0c;他的购买规则如下&#xff1a; 1.必须按照从左…