文章目录

  • Java和Linux实现MySQL数据库备份
  • 前言:
  • 1、为什么要进行数据库备份?
  • 2、数据库备份可以干什么?
  • 1、如何在Java中实现MySQL数据库备份呢?
  • 2、命令执行之Runtime.getRuntime().exec()
  • 3、Java实现数据库备份
  • Linux实现数据库备份
  • 1、定时自动备份并保留7天及数据
  • 2、创建定时任务
  • 3、恢复备份文件


Java和Linux实现MySQL数据库备份

前言:

1、为什么要进行数据库备份?

一、数据丢失应用场景:

  1. 人为操作失误造成某些数据被误操作
  2. 软件 BUG 造成部分数据或全部数据丢失
  3. 硬件故障造成数据库部分数据或全部数据丢失
  4. 安全漏洞被入侵数据恶意破坏

二、非数据丢失应用场景:

  1. 特殊应用场景下基于时间点的数据恢复
  2. 开发测试环境数据库搭建
  3. 相同数据库的新环境搭建
  4. 数据库或者数据迁移

2、数据库备份可以干什么?

  1. 保证数据的安全性
  2. 保证我们因为服务器挂掉导致数据丢失风险降到最低,提高抗风险能力
  3. 当受到网络攻击、入侵、电源故障或者操作失误等事故的发生后,可以完整、快速、简捷、可靠地恢复原有系统,在一定的范围内保障系统的正常运行。

1、如何在Java中实现MySQL数据库备份呢?

我们只需要执行MySQL命令就可以了,Java执行终端命令就是使用exec方法

我们发现Java中的exec方法每次调用执行终端命令都报错

@Test
    public void test() throws IOException, InterruptedException {
        Runtime runtime = Runtime.getRuntime();
        Process process = runtime.exec("mysql --version");
        int i = process.waitFor();
    }

java 实现定时数据库备份 java数据备份功能_java

在windows下相当于直接调用 /开始/搜索程序和文件 的指令 ,比如

Runtime.getRuntime().exec("notepad.exe");  -------打开windows下记事本。

这是因为我们在Windows系统上面需要打开cmd窗口才能执行终端命令,不然找不到对应的路径

优化:

2、命令执行之Runtime.getRuntime().exec()

在java中,RunTime.getRuntime().exec()实现了调用服务器命令脚本来执行功能需要。

用法:

public Process exec(String command)-----在单独的进程中执行指定的字符串命令。
public Process exec(String [] cmdArray)---在单独的进程中执行指定命令和变量
public Process exec(String command, String [] envp)----在指定环境的独立进程中执行指定命令和变量
public Process exec(String [] cmdArray, String [] envp)----在指定环境的独立进程中执行指定的命令和变量
public Process exec(String command,String[] envp,File dir)----在有指定环境和工作目录的独立进程中执行指定的字符串命令
public Process exec(String[] cmdarray,String[] envp,File dir)----在指定环境和工作目录的独立进程中执行指定的命令和变量

Linux系统下:

使用以下命令就能执行终端命令

Runtime.getRuntime().exec(new String[]{"/bin/sh","-c", cmds});

Windows下:

使用以下命令就能执行终端命令

Runtime.getRuntime().exec(new String[]{ "cmd", "/c", cmds});

Process的几种用法:

  1. destroy();杀掉子进程
  2. exitValue();返回子进程的出口值,值0表示正常终止
  3. getErrorStream();获取自己进程错误输出的输入流
  4. getInputStream();这里是获取子进程输出的输入流
  5. getOutputStream();获取子进程输入的输出流
  6. waitFor();导致当前线程等待,如有必要,一直要等到由该Process对象表示的进程已经终止,如果已终止该子进程,此方法立即返回,如果没有终止该子进程,调用的线程将被阻塞,直到推出子进程,根据惯例,0表示正常终止

代码实例:

@Test
    public void test() throws IOException, InterruptedException {
        Runtime runtime = Runtime.getRuntime();
        String [] cmd = {"cmd","/c","mysql --version"};
        Process process = runtime.exec(cmd);
        int i = process.waitFor();
        if (i>0){
            System.out.println("运行终端命令成功");
        }else
        System.out.println("运行终端命令失败");
    }

java 实现定时数据库备份 java数据备份功能_java_02

3、Java实现数据库备份

数据库工具类

/**
 * @author zzw
 * @description TODO
 * @date 2023-04-12 17:35
 */
@Slf4j
public class DataBaseUtils {
    private static final String MYSQL_HOME = "MySQL安装路径"; // MySQL安装路径(注意如果配置了MySQL全局变量,那么这个参数可有可无,没有配置的话,必须要有这个参数,不然会报错,找不到命令)


    /**
     * @description Java代码实现MySQL数据库导出
     *
     * @author zzw
     * @param hostIP MySQL数据库所在服务器地址IP
     * @param userName 进入数据库所需要的用户名
     * @param password 进入数据库所需要的密码
     * @param savePath 数据库导出文件保存路径
     * @param fileName 数据库导出文件文件名
     * @param databaseName 要导出的数据库名
     * @return 返回true表示导出成功,否则返回false。
     */
    public static boolean exportDatabaseTool(String hostIP, String userName, String password, String savePath, String fileName, String databaseName) throws InterruptedException {
        File saveFile = new File(savePath);
        if (!saveFile.exists()) {// 如果目录不存在
            saveFile.mkdirs();// 创建文件夹
        }
        if(!savePath.endsWith(File.separator)){
            savePath = savePath + File.separator;
        }
        PrintWriter pw = null;
        BufferedReader bufferedReader = null;
        try {
            String cmd1 = "/bin/sh";
            String cmd2 = "-c";
            String os_name = System.getProperty("os.name");
            // 判断是否是windows系统
            if (os_name.toLowerCase().startsWith("win")){
                cmd1 = "cmd";
                cmd2 = "/c";
            }
            pw = new PrintWriter(new OutputStreamWriter(new FileOutputStream(savePath + fileName), "utf8"));
            String stmt = DataBaseUtils.MYSQL_HOME + "mysqldump -h" + hostIP + " -u" + userName + " -p" + password + " --set-charset=UTF8 " + databaseName;
            log.info(stmt);
            String[] cmd = { cmd1, cmd2 , stmt };
            Process process = Runtime.getRuntime().exec(cmd);
            InputStreamReader inputStreamReader = new InputStreamReader(process.getInputStream(), "utf8");
            bufferedReader = new BufferedReader(inputStreamReader);
            String line;
            while((line = bufferedReader.readLine())!= null){
                pw.println(line);
            }
            pw.flush();
            if(process.waitFor() == 0){//0 表示线程正常终止。
                return true;
            }
        }catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (bufferedReader != null) {
                    bufferedReader.close();
                }
                if (pw != null) {
                    pw.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return false;
    }


    /**
     * 用来恢复数据库
     * @param filepath 数据库备份的脚本路径
     * @param ip IP地址
     * @param database 数据库名称
     * @param userName 用户名
     * @param password 密码
     * @return
     */
    public static boolean recover(String filepath,String ip,String database, String userName,String password) {
        String cmd1 = "/bin/sh";
        String cmd2 = "-c";
        String os_name = System.getProperty("os.name");
        // 判断是否是windows系统
        if (os_name.toLowerCase().startsWith("win")){
            cmd1 = "cmd";
            cmd2 = "/c";
        }
        String stmt2 = DataBaseUtils.MYSQL_HOME + "mysqldump -h "+ip+" -u"+userName+" -p"+password+" "+database+" < " + filepath;
        String[] cmd = { cmd1, cmd2, stmt2 };
        try {
            log.info(cmd[2]);
            Runtime.getRuntime().exec(cmd);
            log.info("数据已从 " + filepath + " 导入到数据库中");
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    @Test
    public void test() throws IOException, InterruptedException {
        System.out.println(exportDatabaseTool("IP", "用户名", "密码", "下载位置",
                "文件名.sql", "数据库"));
//        System.out.println(recover("下载位置.sql", "IP", "数据库", "用户名", "密码"));
    }
}

定时任务工具类:想学习定时任务的可以点击此链接:

/**
 * @author zzw
 * @description TODO 定时任务实现数据库备份
 * @date 2023-04-12 17:32
 */
@Configuration
@EnableScheduling
public class Schedule {
@Scheduled(cron = "*/5 * * * * ?") // 每五秒钟执行一次定时任务
	private void ddd(){
	   try {
	        DataBaseUtils.exportDatabaseTool("IP", "用户名", "密码", "下载位置",
	                  "文件名.sql", "数据库");
	   } catch (InterruptedException e) {
	             e.printStackTrace();
	   }
	}
}

Linux实现数据库备份

1、定时自动备份并保留7天及数据

移动到home文件夹下

cd  /home

创建文件夹 

mkdir sqlbackup

移动到sqlbackup

cd /home/sqlbackup

创建并编辑备份shell脚本

vim DatabaseName.sh

按键i插入

粘贴代码

java 实现定时数据库备份 java数据备份功能_java_03

#!/bin/bash

baseDir="/home/sqlbackup/";

cd "$baseDir";

echo "开始备份数据库";

#不压缩(压缩不压缩可自行选择)

#echo 'mysqldump -uroot -pt84QBp^@mb6x DatabaseName > /home/sqlbackup/DatabaseName_$(date +%Y%m%d_%H%M%S).sql';

#压缩

# mysql_location 安装路径,如果配置了全局路径就可以把这个参数去掉

mysql_location="MySQL安装路径/bin/"

echo `${mysql_location}mysqldump -uroot -proot test| gzip > /home/sqlbackup/test_$(date +%Y%m%d_%H%M%S).sql.gz`;

echo "备份数据完成";

oldDate=`date --date='-7 minutes' +%Y%m%d_%H%M`;

#删除当前日期-七天前的备份

echo `rm -rf test_$oldDate*`;

echo "删除$oldDate的备份成功"

#now=$(date +"%Y-%m-%d_%H-%M-%S");

#old=$(date --date="-7 minutes" +"%Y-%m-%d_%H-%M");

#echo `mysqldump -uroot -proot test | gzip > $now.sql.gz`;

#echo `find . -type f -name "*.sql.gz" -mtime +0 -newermt "$oldDate" -delete`;

ESC 输入冒号 :wq 保存并退出 q 退出 后面加!强制效果

测试脚本是否正常: ./DatabaseName.sh

java 实现定时数据库备份 java数据备份功能_sql_04

正常是生成这种文件:

java 实现定时数据库备份 java数据备份功能_java_05

报错:-bash: ./DatabaseName.sh: Permission denied

没有权限:需要添加权限

chmod 777 DatabaseName.sh

2、创建定时任务

定时任务规则:

输入

java 实现定时数据库备份 java数据备份功能_数据库_06

crontab -e

进入自动任务设置文件后 输入以下代码

*/1 * * * * /home/sqlbackup/DatabaseName.sh  每分钟执行

0 2 * * * /home/sqlbackup/DatabaseName.sh  每天2点执行

此代码 代表每分钟执行一次/home/sqlbackup文件夹下的DatabaseName.sh文件

五个*分别代表 分 时 天 月 周

java 实现定时数据库备份 java数据备份功能_数据库_07

重启crond服务:service crond restart

定时任务重启报错解决方案:
错误:Redirecting to /bin/systemctl restart crond.service

/bin/systemctl restart crond

相关解决方案:

3、恢复备份文件

创建my_mysql.cnf 文件

java 实现定时数据库备份 java数据备份功能_java 实现定时数据库备份_08

vim my_mysql.cnf

java 实现定时数据库备份 java数据备份功能_数据库_09

[mysqldump]

max_allowed_packet= 400M

host=127.0.0.1

user=root

password='123456' # 设置为自己的密码例如我的为123456

[mysql]

host=127.0.0.1

user=root

password='123456'

创建mysql_restore.sh文件

java 实现定时数据库备份 java数据备份功能_java_10

vim mysql_restore.sh

粘贴代码

java 实现定时数据库备份 java数据备份功能_mysql_11

脚本内容:

#!/bin/bash

if [ -z $1 ] || [ ! -f $1 ]

then

  echo "请输入sql压缩文件(*.sql.gz)"

  exit 1

fi

db_name='test ' #需要导入的的文件名

base_dir='/home/sqlbackup/'

gz_sql_file=`basename $1`

file_ext=${gz_sql_file##*.}

if [ $file_ext != 'gz' ]

then

  echo '文件格式不正确,请输入 .sql.gz 文件'

  exit 1

fi

sql_file=${gz_sql_file%.*}

echo '解压文件中...'

gzip -dc $base_dir$gz_sql_file > $base_dir$sql_file

echo '解压完成.'

echo '开始导入数据库...'

mysql --defaults-extra-file=/home/sqlbackup/my_mysql.cnf $db_name < $base_dir$sql_file

if [ -f $base_dir$sql_file ]

then

  echo '删除临时文件.'

  rm -f $base_dir$sql_file

fi

echo '导入完成.'i

ESC 输入冒号 :wq 保存并退出 q 退出 后面加!强制效果

启动测试

java 实现定时数据库备份 java数据备份功能_java_12

注意:如果整个库被被删了 需要先创建库 否则报错

java 实现定时数据库备份 java数据备份功能_sql_13