您的位置:首页 > 数据库 > MySQL

免 mysqldump 命令备份 MySQL 数据库

2020-02-10 17:01 120 查看

使用官方提供的 mysqldump 命令可以轻松地备份SQL,但是通常应用服务器和数据库服务器不是放在一块的儿,是否可以通过纯 Java 或 JDBC 来实现备份呢?答案是可以的,笔者根据此思路进行了与 AJAJX-Data 的整合,代码行数更精简,只有 200 多行代码。

但是,必须指出,这种思路有不少缺点,自然是不能代替官方工具的了。备份表结构通过 SHOW CREATE TABLE 语句完成,——这个没问题,只是备份实体数据时,是通过 SELECT * FROM table 备份所有行的,200 多行的代码可见考虑的情况不是很全,有其数据类型没有加进来,只能说可以应付普通的情况了。第二是效率问题,通过 JDBC 和 SELECT * 扫描表,数据量大的时候可见是不理想的。

要说靠谱自然是官方的工具完善,本文提供的思路权且当作一种应急的功能,“有备份总比没有好”,而且也不用央求运维帮忙啦

完整代码如下。

package com.ajaxjs.backup;

import java.io.IOException;
import java.sql.Connection;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Types;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

import com.ajaxjs.orm.JdbcReader;
import com.ajaxjs.util.CommonUtil;
import com.ajaxjs.util.io.FileHelper;
import com.ajaxjs.util.logger.LogHelper;

/**
* 免 mysqldump 命令备份 SQL
*
* @author frank
*
*/
public class MysqlExport {
private static final LogHelper LOGGER = LogHelper.getLog(MysqlExport.class);

/**
* 创建 MysqlExport 对象
*
* @param conn         数据库连接对象
* @param databaseName 数据库库名
* @param saveFolder   保存目录
*/
public MysqlExport(Connection conn, String databaseName, String saveFolder) {
this.databaseName = databaseName;
this.saveFolder = saveFolder;

try {
stmt = conn.createStatement();
} catch (SQLException e) {
LOGGER.warning(e);
}
}

private static final String SQL_START_PATTERN = "-- start";
private static final String SQL_END_PATTERN = "-- end";

private Statement stmt;
private String databaseName;
private String saveFolder;

/**
* 获取当前数据库下的所有表名称
*
* @return List\<String\> 所有表名称
*/
private List<String> getAllTables() {
List<String> tables = new ArrayList<>();

JdbcReader.rsHandle(stmt, "SHOW TABLE STATUS FROM `" + databaseName + "`;", rs -> {
try {
while (rs.next())
tables.add(rs.getString("Name"));
} catch (SQLException e) {
LOGGER.warning(e);
}
});

return tables;
}

/**
* 生成create语句
*
* @param table 表名
* @return String
*/
private String getTableInsertStatement(String table) {
StringBuilder sql = new StringBuilder();

JdbcReader.rsHandle(stmt, "SHOW CREATE TABLE `" + table + "`;", rs -> {
try {
while (rs.next()) {
String qtbl = rs.getString(1), query = rs.getString(2);
query = query.trim().replace("CREATE TABLE", "CREATE TABLE IF NOT EXISTS");

sql.append("\n\n--");
sql.append("\n").append(SQL_START_PATTERN).append("  table dump : ").append(qtbl);
sql.append("\n--\n\n");
sql.append(query).append(";\n\n");
}

sql.append("\n\n--\n").append(SQL_END_PATTERN).append("  table dump : ").append(table)
.append("\n--\n\n");
} catch (SQLException e) {
LOGGER.warning(e);
}
});

return sql.toString();
}

/**
* 生成insert语句
*
* @param table the table to get inserts statement for
* @return String generated SQL insert
*/
private String getDataInsertStatement(String table) {
StringBuilder sql = new StringBuilder();
JdbcReader.rsHandle(stmt, "SELECT * FROM " + "`" + table + "`;", rs -> {
try {
rs.last();
//				int rowCount = rs.getRow();
//			if (rowCount <= 0)
//				return sql.toString();

sql.append("\n--").append("\n-- Inserts of ").append(table).append("\n--\n\n");
sql.append("\n/*!40000 ALTER TABLE `").append(table).append("` DISABLE KEYS */;\n");
sql.append("\n--\n").append(SQL_START_PATTERN).append(" table insert : ").append(table)
.append("\n--\n");
sql.append("INSERT INTO `").append(table).append("`(");

ResultSetMetaData metaData = rs.getMetaData();
int columnCount = metaData.getColumnCount();

for (int i = 0; i < columnCount; i++) {
sql.append("`").append(metaData.getColumnName(i + 1)).append("`, ");
}

sql.deleteCharAt(sql.length() - 1).deleteCharAt(sql.length() - 1).append(") VALUES \n");

rs.beforeFirst();
while (rs.next()) {
sql.append("(");
for (int i = 0; i < columnCount; i++) {

int columnType = metaData.getColumnType(i + 1);
int columnIndex = i + 1;

if (Objects.isNull(rs.getObject(columnIndex))) {
sql.append("").append(rs.getObject(columnIndex)).append(", ");
} else if (columnType == Types.INTEGER || columnType == Types.TINYINT
|| columnType == Types.BIT) {
sql.append(rs.getInt(columnIndex)).append(", ");
} else {
String val = rs.getString(columnIndex).replace("'", "\\'");
sql.append("'").append(val).append("', ");
}
}

sql.deleteCharAt(sql.length() - 1).deleteCharAt(sql.length() - 1);
sql.append(rs.isLast() ? ")" : "),\n");
}
} catch (SQLException e) {
LOGGER.warning(e);
}
});

sql.append(";\n--\n").append(SQL_END_PATTERN).append(" table insert : ").append(table).append("\n--\n");
// enable FK constraint
sql.append("\n/*!40000 ALTER TABLE `").append(table).append("` ENABLE KEYS */;\n");

return sql.toString();
}

/**
* 导出所有表的结构和数据
*
* @return String
*/
private String exportToSql() {
StringBuilder sql = new StringBuilder();
sql.append("--\n-- Generated by AJAXJS-Data");
sql.append("\n-- Date: ").append(CommonUtil.now("d-M-Y H:m:s")).append("\n--");

// these declarations are extracted from HeidiSQL
sql.append("\n\n/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;")
.append("\n/*!40101 SET NAMES utf8 */;\n/*!50503 SET NAMES utf8mb4 */;")
.append("\n/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;")
.append("\n/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;");

List<String> tables = getAllTables();

for (String s : tables) {
sql.append(getTableInsertStatement(s.trim()));
sql.append(getDataInsertStatement(s.trim()));
}

sql.append("\n/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */;").append(
"\n/*!40014 SET FOREIGN_KEY_CHECKS=IF(@OLD_FOREIGN_KEY_CHECKS IS NULL, 1, @OLD_FOREIGN_KEY_CHECKS) */;")
.append("\n/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;");

return sql.toString();
}

/**
* 执行导出
*
*/
public void export() {
String sqlFile = saveFolder + FileHelper.separator + CommonUtil.now("yyyy_MM_dd_HH_mm_ss") + "_" + databaseName
+ "_database_dump.sql";

FileHelper.saveText(sqlFile, exportToSql());
// 压缩 zip

//		// zip the file
//		zipFileName = saveFolder + "/" + sqlFileName.replace(".sql", ".zip");
//		File generatedZipFile = new File(zipFileName);
//		ZipUtil.pack(sqlFolder, generatedZipFile);
//
//		// clear the generated temp files
//		clearTempFiles(true);
}

}

最新版本在 https://gitee.com/sp42_admin/ajaxjs/blob/master/ajaxjs-data/src/main/java/com/ajaxjs/backup/MysqlExport.java

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: