前言

  MySQL数据库是一种比较昂贵的资源,存储的数据必须是高价值的数据。对于一些存储在MySQL中,数据不变,且基本用不到的表。有时可以拉取下来备份到文件系统当中了,节约成本。本文将讲述用Java代码从MySQL中拉取数据库表为sql脚本,然后将其压缩为zip文件,节省空间。

实现原理

导出mysql数据为sql文本时用到的命令是:

###关键字和用户名之类的没有空格隔开,最后没有分号;
mysqldump -uUserName -pPassWord -hHost -PPort database tablename > D:\test\123.sql

执行过程:

  1. 先在MySQL的安装bin目录打开命令窗口(cmd)。
  2. 在输出目录查看文件,也可以不带盘符,默认为bin目录。

Java实现导出

获取表名

##假如每次获取该数据库中的1张表
SELECT
	TABLE_NAME 
FROM
	information_schema.TABLES 
WHERE
	TABLE_SCHEMA = ( SELECT DATABASE ( ) ) 
ORDER BY
	TABLE_NAME ASC 
	LIMIT 1

构建压缩后的文件名称

##tableName从上面得来
String zipName="src/main/resources/temp/"+tableName+".zip";

读取流并压缩

/**
     * 拉取sql文件并压缩sql文件为zip文件
     * 
     * @throws IOException
     *             IO异常
     */
    public void getAndZip(String tableName, String zipName) throws IOException {

        InputStream is = null;
        OutputStream os = null;
        ZipOutputStream zos = null;

        String sqlName = tableName + ".sql";

        // 构造sql命令
        StringBuilder command = new StringBuilder();

        // 构建导出sql命令:此处的数据库及其名称需要事先定义好
        command.append("mysqldump -u").append(userName).append(" -p").append(passWord).append(" -h").append(host).append(" -P").append("3306").append(" ")
                .append(table).append(" ").append(tableName);

        try {

            // 执行导出
            Process pro = Runtime.getRuntime().exec(command.toString());

            // 获取输入流,到了这一步基本完成了,如果只需要sql文本文件,这此时就可以自己将输入流读取为文本,不需要在进行下面的操作
            is = pro.getInputStream();

            os = new FileOutputStream(zipName);

            // 压缩
            zos = new ZipOutputStream(os);

            // 这个是压缩sql文件,利用文件名创建条目sqlname以.sql结尾
            ZipEntry zipEntry = new ZipEntry(sqlName);
			//放进Entry
            zos.putNextEntry(zipEntry);

            // 读取完后无数据,即为-1
            int count = -1;

            // 每次读取16MB,内存能够支持,这里是依次写入,而不是一次性写入
            byte[] bytes = new byte[LENGTH_16MB];

            // 每次写16MB
            while ((count = is.read(bytes)) != -1) {

                // 写一次刷一次
                zos.write(bytes, 0, count);
                zos.flush();
            }
        } catch (IOException e) {

          //日志记录
        } catch (Exception e) {

           //日志记录
        } finally {

            // 关闭流,注意顺序,一旦错了,会出现意想不到的错误。
            close(zos, os, is);
        }
    }

下面是一个关闭多个流的简单方法

/**
     * 多个关闭的简单方法
     */
    private void close(Closeable... closeables) {

        // 空直接返回
        if (closeables == null || closeables.length == 0) {
            return;
        }

        // 循环关闭流
        for (Closeable closeable : closeables) {
            try {
                if (Objects.nonNull(closeable)) {
                    closeable.close();
                }
            } catch (Exception e) {
                LOG.error("关闭流异常:{}", e);
            }
        }
    }

注意事项

  1. mysqldump命令是window下面的命令,代码在本地可能运行良好,但是发到Linux服务器上基本会出现异常,此时需要运维的帮助,在Linux的MySQL中打入mysqlld.exe还是mysqldump.exe镜像,具体哪一个忘了。
  2. 流的关闭一定要遵从进行实例化操作的关闭。或者直接使用Java8及以上的try_resource写法,最省事。