枚举类
Java
复制代码
import lombok.Getter;
import java.util.List;
@Getter
public enum BackupTypeEnum {
ALARM_RECORD("ALARM_RECORD", List.of("fix_alarm_record"), "alarm_record", "报警记录"),
DEVICE_RECORD("DEVICE_RECORD", List.of("fix_device_record"), "device_record", "设备记录"),
FAULT_RECORD("FAULT_RECORD", List.of("fix_fault", "fix_fault_dict", "fix_fault_repair"), "", "故障记录"),
AUTO_RECORD("AUTO_RECORD", List.of("fix_record_base_data", "fix_record_co2_data", "fix_record_detail"), "auto", "多参数据");
private final String type;
private final List<String> tableNames;
private final String folder;
private final String desc;
BackupTypeEnum(String type, List<String> tableNames, String folder, String desc) {
this.type = type;
this.tableNames = tableNames;
this.folder = folder;
this.desc = desc;
}
}
类方法
Java
复制代码
/**
* 手动备份入口
*/
@Override
public Boolean backup(String type) {
BackupTypeEnum backupType = BackupTypeEnum.valueOf(type);
String tenantId = LoginHelper.getTenantId();
File sqlFile = null;
try {
// 1. 导出SQL
sqlFile = dumpTables(backupType);
// 2. 读取文件
byte[] bytes = Files.readAllBytes(sqlFile.toPath());
// 3. 文件名
String fileName =
backupType.getType() + "_" +
LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss")) +
".sql";
// 4. 上传OSS
Long ossId = ossService.uploadFile(bytes, fileName, "application/sql");
// 5. 保存OSS记录
GisOss oss = new GisOss();
oss.setSysOssId(ossId);
oss.setKeyId(Long.parseLong(tenantId));
oss.setFileTable(String.join(",", backupType.getTableNames()));
oss.setFileType(type);
oss.setFileDetailType(backupType.getFolder());
gisOssMapper.insert(oss);
// 6. 保存备份记录
FixDataBackupRecord record = new FixDataBackupRecord();
record.setBackupName(backupType.getDesc());
record.setBackupType(backupType.getType());
record.setBackupMode("MANUAL");
record.setBackupTime(new Date());
record.setOssId(ossId);
record.setBackupNickName(
LoginHelper.getLoginUser().getNickname()
);
backupRecordMapper.insert(record);
return true;
} catch (Exception e) {
log.error("备份失败 type={}", type, e);
throw new ServiceException("数据库备份失败:" + e.getMessage());
} finally {
// 删除临时文件
if (sqlFile != null && sqlFile.exists()) {
if (!sqlFile.delete()) {
log.warn("临时文件删除失败:{}", sqlFile.getAbsolutePath());
}
}
}
}
/**
* 多表导出
*/
private File dumpTables(BackupTypeEnum backupType)
throws IOException, InterruptedException {
// 1. 读取主库配置
DynamicDataSourceProperties.DataSourceConfig master =
dsProps.getDatasource().get("master");
if (master == null) {
throw new ServiceException("找不到 master 数据源配置");
}
JdbcInfo jdbc = JdbcInfo.parse(master.getUrl());
boolean isWindows =
System.getProperty("os.name").toLowerCase().contains("win");
// 2. 创建临时文件
String tmpDir = System.getProperty("java.io.tmpdir");
String fileName =
backupType.getType() + "_" +
System.currentTimeMillis() + ".sql";
File outputFile = new File(tmpDir, fileName);
log.info("开始备份:{} -> {}",
backupType.getTableNames(),
outputFile.getAbsolutePath()
);
if (isWindows) {
dumpForWindows(master, jdbc, backupType, outputFile);
} else {
dumpForLinux(master, jdbc, backupType, outputFile);
}
// 3. 校验
if (!outputFile.exists() || outputFile.length() == 0) {
throw new ServiceException("备份文件为空");
}
log.info("备份成功,大小={}KB",
outputFile.length() / 1024
);
return outputFile;
}
/**
* Windows导出
*/
private void dumpForWindows(
DynamicDataSourceProperties.DataSourceConfig master,
JdbcInfo jdbc,
BackupTypeEnum backupType,
File outputFile
) throws IOException, InterruptedException {
String tables =
String.join(" ", backupType.getTableNames());
String cmd =
"mysqldump " +
"-u" + master.getUsername() + " " +
"-p" + master.getPassword() + " " +
jdbc.getDbName() + " " +
tables +
" -r \"" + outputFile.getAbsolutePath() + "\"";
Process process = Runtime.getRuntime().exec(cmd);
String err = readProcessOutput(process.getErrorStream());
int code = process.waitFor();
if (code != 0) {
throw new ServiceException(
"mysqldump失败(Windows): " + err
);
}
}
/**
* Linux导出(推荐方式)
*/
private void dumpForLinux(
DynamicDataSourceProperties.DataSourceConfig master,
JdbcInfo jdbc,
BackupTypeEnum backupType,
File outputFile
) throws IOException, InterruptedException {
ProcessBuilder pb = new ProcessBuilder();
// 密码走环境变量(安全)
pb.environment().put(
"MYSQL_PWD",
master.getPassword()
);
List<String> cmd = new ArrayList<>();
cmd.add("mysqldump");
cmd.add("-h" + jdbc.getHost());
cmd.add("-P" + jdbc.getPort());
cmd.add("-u" + master.getUsername());
cmd.add("--single-transaction");
cmd.add("--skip-lock-tables");
cmd.add("--skip-comments");
cmd.add("--complete-insert");
// 数据库
cmd.add(jdbc.getDbName());
// 多表
cmd.addAll(backupType.getTableNames());
pb.command(cmd);
pb.redirectOutput(outputFile);
pb.redirectErrorStream(true);
Process process = pb.start();
int code = process.waitFor();
if (code != 0) {
String msg =
readProcessOutput(process.getInputStream());
throw new ServiceException(
"mysqldump失败(Linux): " + msg
);
}
}
/**
* 读取进程输出
*/
private String readProcessOutput(
java.io.InputStream inputStream
) throws IOException {
StringBuilder sb = new StringBuilder();
try (BufferedReader reader =
new BufferedReader(
new InputStreamReader(inputStream))) {
String line;
while ((line = reader.readLine()) != null) {
sb.append(line).append("\n");
}
}
return sb.toString();
}
}