코드로 직접 이동하세요. 더 나은 솔루션이 있으면 모두가 함께 진행할 수 있도록 직접 공유할 수 있습니다.
//每天2:10执行
//@Scheduled(cron = "0 0/2 * * * ?")
public void BackUpFileTasks() {
try {
semaphoreGetSealRandom.acquire();
logger.info("...BackUpFileTasks start...");
DuplicateCatalog duplicateCatalog = new DuplicateCatalog();
ExecutorService executorService = Executors.newFixedThreadPool(2);
FutureTask<String> future = new FutureTask<>(
new Callable<String>() {
public String call() {
//备份数据库
duplicateCatalog.backUpMysql();
return "...";
}
});
// 加载future
Future<?> submit = executorService.submit(future);
Future<Boolean> booleanFuture = executorService.submit(new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
//备份文件夹
return duplicateCatalog.fileToZip();
}
});
try {
System.out.println(submit.get(10, TimeUnit.SECONDS));
booleanFuture.get(60,TimeUnit.MILLISECONDS);
} catch (Exception e) {
logger.error("备份数据库超时!"); // 超时报个错
future.cancel(Boolean.TRUE);
} finally {
executorService.shutdown(); // 关闭线程池
}
//删除之前备份文件夹
duplicateCatalog.deleteBackUpFile();
//备份文件夹
duplicateCatalog.fileToZip();
//备份程序包
duplicateCatalog.backProject();
logger.info("...BackUpFileTasks end...");
} catch (Throwable e) {
logger.error("备份数据:", e);
} finally {
semaphoreGetSealRandom.release(); //返回一个信号量
}
}
/**
* @Author libai
* @Date 2023/2/17 9:40
*/
public class DuplicateCatalog {
// 保存temp里面内容
private List<String> listFile = new ArrayList<String>();
private Logger logger = LoggerFactory.getLogger(DuplicateCatalog.class);
/**
* 数据库用户名
*/
@Value("${database.username}")
private String username;
/**
* 数据库密码
*/
@Value("${database.password}")
private String password;
/**
* 数据库url
*/
@Value("${database.url}")
private String url;
/**
* 数据库类型
*/
@Value("${spring.profiles.active}")
private String type;
/**
* 文件存储路径
*/
@Value("${upload.path}")
private String zippath;
//备份地址
private String tmppath = "";
//windows dm数据库bin目录
private String dmpath = "D:\\kaifa\\dmdatabase\\dmdbms\\bin ";
//linux dm数据库bin目录
private String dmlinuxpath = "/opt/dmdbms/bin ";
//Linux mysqldump所在路径
private String mysqldumppath = "/usr/bin/mysqldump ";
//备份数据库
public void backUpMysql() {
zippath = zippath + "\\";
Calendar cal = new GregorianCalendar();
cal.setTime(new Date());
String year = Integer.toString(cal.get(Calendar.YEAR));
Integer month = cal.get(Calendar.MONTH) + 1;
Integer day = cal.get(Calendar.DATE);
String os = System.getProperty("os.name");
if (os.toLowerCase().startsWith("lin")) {
zippath = "/opt/temp/";
}
tmppath = zippath + year + "-" + (month >= 10 ? month : "0" + month) + "-" + (day >= 10 ? day : "0" + day) + "备份";
File saveFile = new File(tmppath);
// 如果目录不存在
if (!saveFile.exists()) {
// 创建文件夹
saveFile.mkdirs();
}
Process proc = null;
Runtime run = Runtime.getRuntime();
if ("mysql".equals(type)) {
try {
String backPath = "";
//拼接sql文件名称
String fileName = "/" + new SimpleDateFormat("yyyyMMdd_HHmmss").format(System.currentTimeMillis()) + ".sql";
backPath = tmppath + fileName;
//开始拼接命令
StringBuilder command = appendCmd(backPath);
// 调用外部执行exe文件的javaAPI
logger.info("执行mysql指令:" + command);
logger.info("OS Name:" + os);
try {
if (os.toLowerCase().startsWith("win")) {
proc = Runtime.getRuntime().exec(command.toString());
} else {
proc = Runtime.getRuntime().exec(new String[]{"/bin/bash", "-c", command.toString()});
}
} catch (IOException e) {
e.printStackTrace();
}
// 0 表示线程正常终止。
Integer waitFor = proc.waitFor();
Integer exitValue = proc.exitValue();
logger.info("proc.waitFor()-proc.exitValue()===>{},{}", waitFor, exitValue);
try {
InputStream errorStream = proc.getErrorStream();
File file = new File(tmppath + "/备份error/");
writeToLocal(file.getPath() + "日志.txt", errorStream);
} catch (Exception e) {
logger.info("未产生异常信息,备份正常");
}
if (waitFor != 0) {
logger.info("===========backup failure================");
} else {
logger.info("===========backup successful================");
proc.destroy();
}
} catch (InterruptedException e) {
logger.info("backUpSystemLogs InterruptedException", e);
e.printStackTrace();
throw new RuntimeException(e.getMessage());
} catch (Throwable e) {
logger.info("appear Throwable--------->");
e.printStackTrace();
}
if (logger.isDebugEnabled()) {
logger.debug("Execute MysqlDumpExec::backUpSystemLogs() end.");
}
} else if ("rdjc".equals(type)) {
System.out.println(5);
} else {
//达梦数据库备份
logger.info("dm数据库备份开始");
try {
if (os.toLowerCase().startsWith("lin")) {
proc = run.exec("/bin/bash");
} else {
proc = run.exec("cmd");
}
} catch (IOException e) {
e.printStackTrace();
}
String dmlIp = "";
String dmPort = "";
String dmName = "";
if (StringUtils.isNotBlank(url)) {
//从配置中解析出数据库ip+名+端口
String[] datas = url.split("\\?")[0].split("/");
dmName = datas[datas.length - 1];
String allIp = datas[datas.length - 2];
String[] ips = allIp.split(":");
dmlIp = ips[0];
dmPort = ips[1];
}
if (proc != null) {
try {
if (os.toLowerCase().startsWith("lin")) {
String command = "cd " + dmlinuxpath + " && ./dexp " + username + "/" + password + "@" + dmlIp + ":" + dmPort +
" file=" + dmName + ".dmp NOLOG=Y LOG=dm备份日志.log SCHEMAS=" + dmName + " directory=" + tmppath;
proc = run.exec(new String[]{"/bin/bash", "-c", command});
} else {
proc = run.exec("cmd /c cd /d " + dmpath + " && dexp " + username + "/" + password + "@" + dmlIp + ":" + dmPort +
" file=" + dmName + ".dmp NOLOG=Y LOG=dm备份日志.log SCHEMAS=" + dmName + " directory=" + tmppath);
}
InputStreamReader inst = null;
SequenceInputStream sis = new SequenceInputStream(proc.getInputStream(), proc.getErrorStream());
if (os.toLowerCase().startsWith("lin")) {
inst = new InputStreamReader(sis, "UTF-8");//设置编码格式并转换为输入流
} else {
inst = new InputStreamReader(sis, "GBK");//设置编码格式并转换为输入流
}
BufferedReader br = new BufferedReader(inst);//输入流缓冲区
String line = null;
StringBuilder sb = new StringBuilder();
while ((line = br.readLine()) != null) {//循环读取缓冲区中的数据
sb.append(line).append("\n");
}
br.close();
proc.waitFor();
proc.destroy();
logger.info(sb.toString());//输出获取的数据;//输出获取的数据
logger.info("dm数据库备份结束");
} catch (Exception e) {
e.printStackTrace();
logger.error("dm数据库备份异常");
}
}
}
}
/**
* 拼接执行命令
*/
private StringBuilder appendCmd(String backPath) {
StringBuilder command = new StringBuilder();
String mysqlIp = "";
String mysqlPort = "";
String mysqlData = "";
if (StringUtils.isNotBlank(url)) {
//从配置中解析出数据库ip+名+端口
String[] split = url.split("\\?")[0].split("/");
mysqlData = split[split.length - 1];
String allIp = split[split.length - 2];
String[] ips = allIp.split(":");
mysqlIp = ips[0];
mysqlPort = ips[1];
}
// 拼接命令行的命令
// windows: D:\MySQL Server 5.7\bin\mysqldump --opt -h127.0.0.1 --user=root -P33306 --password=123#! --databases test --tables test_user --result-file=D:\logsql\sql.sql --default-character-set=utf8
// linux: /usr/local/mysql/bin/mysqldump --opt -h111.144.210.30 --user=root --password='23!@#' -P33306 --databases test --tables test_t1 test_t2 --result-file=/syslog/backUpSystemLog_20211118_030951_sql.sql
// 区分系统
String os = System.getProperty("os.name");
if (os.toLowerCase().startsWith("win")) {
command.append("cmd.exe /C " + "mysqldump");
} else {
command.append(mysqldumppath).append(" mysqldump");
}
command.append(" --column-statistics=0");
command.append(" --opt -h");
command.append(mysqlIp);
command.append(" --user=");
command.append(username);
if (os.toLowerCase().startsWith("win")) {
command.append(" --password=");
command.append(password);
} else {
//linux需要引号密码,否则会执行失败
command.append(" --password=");
command.append("'" + password + "'");
}
//端口用大写的P指向
command.append(" -P" + mysqlPort);
command.append(" --databases " + mysqlData);
command.append(" --result-file=");
command.append(backPath);
return command;
}
//备份MySQL将错误日志写入txt文件
private void writeToLocal(String destination, InputStream input) throws IOException {
int index;
byte[] bytes = new byte[1024];
FileOutputStream downloadFile = new FileOutputStream(destination);
while ((index = input.read(bytes)) != -1) {
downloadFile.write(bytes, 0, index);
downloadFile.flush();
}
input.close();
downloadFile.close();
}
//备份文件夹
public boolean fileToZip() {
boolean flag = false;
System.out.println("正在压缩中、、、");
long start = System.currentTimeMillis();
getFile(zippath);
String fileName = new SimpleDateFormat("yyyyMMdd_HHmmss").format(System.currentTimeMillis());
try {
File zipFile = new File(tmppath + "/" + fileName + ".zip");
if (zipFile.exists()) {
System.out.println(tmppath + "目录下存在名字为:" + fileName + ".zip" + "的打包文件");
} else {
if (!zipFile.exists()) {
zipFile.getParentFile().mkdirs();
}
flag = Compresseddirectory(zipFile);
}
System.out.println("压缩完成、、、");
long end = System.currentTimeMillis();
System.out.println("用时" + ((end - start) / 1000) + "秒");
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
return flag;
}
//获取文件夹下所有文件路径
private void getFile(String path) {
File file = new File(path);
File[] tempList = file.listFiles();
assert tempList != null;
//如果是空文件夹就删除
if (tempList.length == 0) {
file.delete();
}
for (File f : tempList) {
if (f.isFile()) {
listFile.add(f.getPath());
continue;
}
if (f.isDirectory()) {
getFile(f.getPath());
}
}
}
//执行压缩操作
private boolean Compresseddirectory(File zipFile) {
boolean flag = false;
BufferedInputStream bis = null;
FileInputStream fis = null;
FileOutputStream fos = null;
ZipOutputStream zos = null;
try {
fos = new FileOutputStream(zipFile);
zos = new ZipOutputStream(new BufferedOutputStream(fos));
byte[] bufs = new byte[2048 * 2048];
for (int i = 0; i < listFile.size(); i++) {
try {
//创建ZIP实体,并添加进压缩包
ZipEntry zipEntry = new ZipEntry(listFile.get(i));
zos.putNextEntry(zipEntry);
// 读取待压缩的文件并写进压缩包里
fis = new FileInputStream(listFile.get(i));
bis = new BufferedInputStream(fis, 1024 * 1024);
int read = 0;
while ((read = bis.read(bufs, 0, 1024 * 1024)) != -1) {
zos.write(bufs, 0, read);
}
} catch (Exception e) {
logger.error("文件读取处理有误");
e.printStackTrace();
}
}
flag = true;
listFile.clear();
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException(e);
} finally {
// 关闭流
try {
if (null != bis)
bis.close();
if (null != zos)
zos.close();
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
return flag;
}
//备份程序包
public void backProject() {
System.out.println("复制开始~~~~");
long start = System.currentTimeMillis();
//获取项目位置
URL resource = Thread.currentThread().getContextClassLoader().getResource("");
assert resource != null;
String[] split = resource.toString().split("/");
StringBuilder projectpath = new StringBuilder();
String projectname = "/";
for (int i = 1; i <= split.length; i++) {
projectpath.append(split[i]).append("/");
if (i == split.length - 3) {
projectname += split[i];
break;
}
}
//fileToZip(projectname, tmppath, split[3]);
String newFileName = tmppath + projectname;
String os = System.getProperty("os.name");
File file1 = new File(projectpath.toString());//需要复制的文件/文件夹
if (!file1.exists()) {
file1.mkdir();
}
File file2 = new File(newFileName);//需要复制到的位置
if (!file2.exists()) {
file2.mkdir();
}
if (os.toLowerCase().startsWith("lin")) {
//cp -r /opt/tomcat-sursen/webapps/* /opt/temp/2023-02-17备份
try {
Runtime.getRuntime().exec(new String[]{"/bin/bash", "-c", "cp -r /" + projectpath + "/* " + newFileName});
} catch (IOException e) {
e.printStackTrace();
}
} else {
try {
copy(file1, file2);
} catch (IOException e) {
e.printStackTrace();
System.out.println("copy:error");
}
}
System.out.println("复制结束~~~~");
long end = System.currentTimeMillis();
System.out.println("用时" + ((end - start) / 1000) + "秒");
}
private void copy(File file1, File file2) throws IOException {
File[] files = file1.listFiles();
for (File f : files) {
if (f.isDirectory()) {
File file3 = new File(file2, f.getName());
if (!file3.exists()) {//文件夹不存在
//创建多层文件夹
file3.mkdirs();
}
copy(f, file3);
} else {
String name = f.getName();
File newFile = new File(file2, name);
if (!newFile.exists()) {//文件不存在
//创建文件
newFile.createNewFile();
}
copyFile(f, newFile);
}
}
}
//使用带缓冲区的字符流复制
private void copyFile(File oldFile, File newFile) {
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try {
bis = new BufferedInputStream(new FileInputStream(oldFile));
bos = new BufferedOutputStream(new FileOutputStream(newFile));
byte[] bs = new byte[1024];
int len;
while ((len = bis.read(bs)) != -1) {
bos.write(bs, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (bis != null) {
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (bos != null) {
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
//删除某天备份的数据
public void deleteBackUpFile() {
try {
Calendar now = Calendar.getInstance();
now.add(Calendar.DAY_OF_MONTH, -3);//删除多少天之前备份的文件夹
String endDate = new SimpleDateFormat("yyyy-MM-dd").format(now.getTime());
//按照文件大小升序排序
List<File> files = Arrays.asList(Objects.requireNonNull(new File(zippath).listFiles()));
for (File file : files) {
if (file.getName().contains("备份")) {
/* if ((file.getName().split("签"))[0].compareTo(endDate) < 0) {
System.out.println(file.getPath());
}*/
if (file.getName().compareTo(endDate) < 0) {
deleteFolder(new File(file.getPath()));
logger.info("删除文件夹" + file.getPath());
}
}
}
} catch (Exception e) {
logger.error("删除备份数据异常");
}
}
//递归删除文件夹内的文件
private void deleteFolder(File file) {
for (File subFile : Objects.requireNonNull(file.listFiles())) {
if (subFile.isDirectory()) {
deleteFolder(subFile);
} else {
subFile.delete();
}
}
file.delete();
}
}