免 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
相关文章推荐
- MySQL数据的导出和导入工具:mysqldump(备份数据库的命令)
- MySQL数据的导出和导入工具:mysqldump(备份数据库的命令)
- mysql 数据库备份及恢复命令mysqldump,source的用法
- Mysql--mysqldump命令 备份数据库
- MySQL数据的导出和导入工具:mysqldump(备份数据库的命令)
- mysql在Windows下使用mysqldump命令手动备份数据库和自动备份数据库
- MySQL数据的导出和导入工具:mysqldump(备份数据库的命令) (转)
- MySQL数据的导出和导入工具:mysqldump(备份数据库的命令)
- MySQL数据的导出和导入工具:mysqldump(备份数据库的命令)
- 使用mysql自带工具mysqldump进行全库备份以及source命令恢复数据库
- 在cmd下运行mysql以及使用mysqldump命令导出数据库中的脚本
- MySQL中使用mysqldump命令进行备份与恢复
- Ubuntu下利用mysqldump命令对数据库定时备份
- MySQL备份-mysqldump命令
- 常用mysql命令_备份数据库
- Mysql备份还原数据库之mysqldump实例及参数详细说明
- mysql 命令备份数据库
- 使用mysql 数据库的mysqldump实现自动备份
- mysql命令(数据库备份与恢复)
- MySQL备份命令mysqldump参数说明与示例