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

一、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、执行结果

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

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