mysql实现数据库非常简单,只需要执行
mysqldump -h数据库地址 -P数据库端口 -u用户名 -p用户密码 备份数据库名称 > 指定备份路径和备份文件名。 如下所示:
mysqldump -hlocalhost -P3306 -uroot -proot test > D:\backup\backup.sql
这种方式我们可以通过命令窗口或者 bat脚本实现。但是当面对多数据库的情况时,则需要创建多个脚本,非常不方便管理。
这个时候可以通过创建一个页面的方式,统一对数据库进行备份和还原。
后台实现
一、配置信息
@Value("${spring.datasource.driverClassName}")
private String driverClassName;
@Value("${spring.datasource.druid.master.url}")
private String url;
@Value("${backup.userName}")
private String userName;
@Value("${backup.passWord}")
private String passWord;
@Value("${backup.path}")
private String backupPath;
@Value("${backup.dataBaseIP}")
private String dataBaseIP;
@Value("${backup.dataBasePort}")
private String dataBasePort;
@Value("${backup.shellPath}")
private String shellPath;
private static final String showDataBaseSQL = "SHOW DATABASES;";
这些配置分别是 mysql驱动名称、数据库连接url、 mysql登录用户名、mysql登录密码、备份文件存储路径、 数据库ip地址、数据库端口号、备份脚本地址。
根据自己的业务环境,写在配置文件中即可。
二、创建数据库表
CREATE TABLE `biz_database_backup` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号',
`operation_database` varchar(255) NOT NULL DEFAULT '' COMMENT '操作数据库',
`operation_time` datetime DEFAULT NULL COMMENT '操作时间',
`operation_by` varchar(64) DEFAULT NULL COMMENT ' 操作人',
`backup_path` varchar(255) DEFAULT NULL COMMENT '备份路径',
`backup_file` varchar(255) DEFAULT NULL COMMENT '备份文件',
`restore_time` datetime DEFAULT NULL COMMENT '还原时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8mb3 COMMENT='数据库备份记录表';
数据库表主要用于存储备份的记录,方便进行查看和还原。
CRUD这些后台代码就不展示了,相信大家都是轻车熟路了。
三、启动时创建shell脚本
// 项目启动时创建shell脚本
@PostConstruct
private void createShell() throws IOException {
String shellName = SystemCheckUtils.isLinux() ? "mysql_backup.sh" :
"mysql_backup.bat";
String backupFileName = shellPath + shellName;
String restoreFileName = shellPath + shellName;
File backupFile = new File(backupFileName);
File restoreFile = new File(restoreFileName);
if (!backupFile.exists()) {
// 创建备份脚本
String backupShell = getBackupShell();
Files.write(Paths.get(backupFileName),
backupShell.getBytes(StandardCharsets.UTF_8));
}
if (!restoreFile.exists()) {
// 创建还原脚本
String restoreShell = getRestoreShell();
Files.write(Paths.get(restoreFileName),
restoreShell.getBytes(StandardCharsets.UTF_8));
}
}
private String getBackupShell() {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("mysqldump").append(" -h").append("%1")
.append(" -P").append("%2").append(" -u").append("%3").append(" -p").append("%4")
.append(" ").append("%5").append(" >").append("%6");
return stringBuilder.toString();
}
private String getRestoreShell() {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("mysql").append(" -h").append("%1")
.append(" -P").append("%2").append(" -u").append("%3")
.append(" -p").append("%4").append(" ").append("%5").append(" <").append("%6");
return stringBuilder.toString();
}
因为使用了@PostConstruct注解,所以在项目启动时就会执行createShell()方法,在对应位置创建基础shell脚本。
四、获取需要备份的数据库和需要还原的备份文件
public Map<String, List<String>> getDataBaseName() throws Exception {
Connection connection = getDataBaseConnection();
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery(showDataBaseSQL);
List<String> dataBaseNames = new ArrayList<>();
ResultSetMetaData metaData = resultSet.getMetaData();
while (resultSet.next()) {
int count = metaData.getColumnCount();
for (int i = 0; i < count; i++) {
dataBaseNames.add(resultSet.getString(i + 1));
}
}
File file = new File(backupPath);
if (!file.exists() && !file.isDirectory()) {
file.mkdir();
}
List<String> fileNames = getFileNames(file);
Map<String, List<String>> resultMap = new HashMap<>();
resultMap.put("databaseNames", dataBaseNames);
resultMap.put("fileNames", fileNames);
return resultMap;
}
// 获取数据库连接
private Connection getDataBaseConnection() throws Exception {
Class<?> driverClass = Class.forName(driverClassName);
Driver driver = (Driver) driverClass.getDeclaredConstructor().newInstance();
DriverManager.registerDriver(driver);
return DriverManager.getConnection(url, userName, passWord);
}
// 获取文件夹下所有文件的名称
private List<String> getFileNames(File file) {
List<String> fileNames = new ArrayList<>();
File[] files = file.listFiles();
if (files != null && files.length > 0) {
for (File f: files) {
if (!f.isDirectory()) {
fileNames.add(f.getName());
}
}
}
return fileNames;
}
获取到数据库和备份文件用于页面进行选择需要备份和还原的数据库。
五、domain类
/** 序号 */
private Long id;
/** 备份数据库 */
private String operationDatabase;
/** 备份时间 */
private String operationTime;
/** 备份路径 */
private String backupPath;
/** 备份文件 */
private String backupFile;
/** 备份人 */
private String operationBy;
六、进行备份
public void backupDataBase(@RequestBody DatabaseBackup databaseBackup) throws IOException {
String databaseName = databaseBackup.getOperationDatabase();
String timeNow = DateUtils.getTime();
String dateTimeNow = DateUtils.dateTimeNow();
String backupFile = databaseName + "_" + dateTimeNow + ".sql";
String[] param = new String[7];
DatabaseBackup backup = new DatabaseBackup();
backup.setOperationDatabase(databaseName);
backup.setOperationTime(timeNow);
backup.setOperationBy(SecurityUtils.getUsername());
backup.setBackupPath(backupPath);
backup.setBackupFile(backupFile);
String shellName = SystemCheckUtils.isLinux() ? "mysql_backup.sh" :
"mysql_backup.bat";
this.add(backup);
param[0] = shellPath + shellName;
param[1] = dataBaseIP;
param[2] = dataBasePort;
param[3] = userName;
param[4] = passWord;
param[5] = databaseName;
param[6] = backupPath + backupFile;
Runtime.getRuntime().exec(param);
}
备份时,页面传入需要备份的数据库,然后通过 Runtime.getRuntime().exec(param)方法,调用启动时生成的备份shell脚本。
七、进行还原
public void restoreDataBase(@RequestBody DatabaseBackup databaseBackup) throws IOException {
String databaseName = databaseBackup.getOperationDatabase();
String shellName = SystemCheckUtils.isLinux() ? "mysql_restore.sh" :
"mysql_restore.bat";
String[] param = new String[7];
param[0] = shellPath + shellName;
param[1] = dataBaseIP;
param[2] = dataBasePort;
param[3] = userName;
param[4] = passWord;
param[5] = databaseName;
param[6] = backupPath + databaseBackup.getBackupFile();
Runtime.getRuntime().exec(param);
}
还原时,页面传入需要还原的数据库,以及还原的sql脚本。然后通过 Runtime.getRuntime().exec(param)方法,调用启动时生成的还原shell脚本。
八、页面效果