perf:增加数据库备份
This commit is contained in:
33
springboot-database/pom.xml
Normal file
33
springboot-database/pom.xml
Normal file
@@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.tiesheng.springboot-parent</groupId>
|
||||
<artifactId>springboot-parent</artifactId>
|
||||
<version>0.5.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>springboot-database</artifactId>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.tiesheng.springboot-parent</groupId>
|
||||
<artifactId>springboot-util</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.tiesheng.database;
|
||||
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
|
||||
/**
|
||||
* @author hao
|
||||
*/
|
||||
@ComponentScan({
|
||||
"com.tiesheng.database.**.*"
|
||||
})
|
||||
public class DatabaseAutoConfigurer {
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package com.tiesheng.database.config;
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.util.RuntimeUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @author hao
|
||||
*/
|
||||
@Configuration
|
||||
@ConfigurationProperties(prefix = "tiesheng.db-backup")
|
||||
public class DbBackupConfig {
|
||||
|
||||
/**
|
||||
* 数据库备份的路径
|
||||
*/
|
||||
private String path = "/root/backup/";
|
||||
|
||||
/**
|
||||
* 备份文件的时间格式
|
||||
*/
|
||||
private String format = "yyyyMMdd";
|
||||
|
||||
|
||||
@PostConstruct
|
||||
public void dbBackup() {
|
||||
String url = SpringUtil.getProperty("spring.datasource.url");
|
||||
String username = SpringUtil.getProperty("spring.datasource.username");
|
||||
String password = SpringUtil.getProperty("spring.datasource.password");
|
||||
|
||||
try {
|
||||
RuntimeUtil.exec(StrUtil.format("mysqldump -u{} -p{} {} > {}{}.sql", username, password, username,
|
||||
getPath(), DateUtil.format(new Date(), format)
|
||||
));
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// setter\getter
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
public void setPath(String path) {
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
public String getFormat() {
|
||||
return format;
|
||||
}
|
||||
|
||||
public void setFormat(String format) {
|
||||
this.format = format;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package com.tiesheng.database.config;
|
||||
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.db.Db;
|
||||
import cn.hutool.db.Entity;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 数据库表版本对比
|
||||
*
|
||||
* @author hao
|
||||
*/
|
||||
@Configuration
|
||||
@ConfigurationProperties(prefix = "tiesheng.db-migration")
|
||||
public class DbMigrationConfig {
|
||||
|
||||
private String table = "core_config_db";
|
||||
private List<String> locations = CollUtil.newArrayList("classpath*:db/migration/*.sql");
|
||||
private String ignoreSqls = "drop table,delete from";
|
||||
|
||||
/**
|
||||
* 检查数据库是否存在
|
||||
*
|
||||
* @param db
|
||||
* @throws SQLException
|
||||
*/
|
||||
public void checkDbExists(Db db) throws SQLException {
|
||||
try {
|
||||
db.count(Entity.create(getTable()));
|
||||
} catch (SQLException ignored) {
|
||||
db.execute("CREATE TABLE `" + getTable() + "` (\n" +
|
||||
" `id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,\n" +
|
||||
" `create_time` datetime(0) NOT NULL,\n" +
|
||||
" `update_time` datetime(0) NOT NULL,\n" +
|
||||
" `is_deleted` int(6) NOT NULL DEFAULT 0,\n" +
|
||||
" `file` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '文件名称',\n" +
|
||||
" `checksum` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '文件checksum',\n" +
|
||||
" PRIMARY KEY (`id`) USING BTREE\n" +
|
||||
") ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '配置-数据库' ROW_FORMAT = Dynamic;");
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// setter\getter
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public String getTable() {
|
||||
return table;
|
||||
}
|
||||
|
||||
public void setTable(String table) {
|
||||
this.table = table;
|
||||
}
|
||||
|
||||
public List<String> getLocations() {
|
||||
return locations;
|
||||
}
|
||||
|
||||
public void setLocations(List<String> locations) {
|
||||
this.locations = locations;
|
||||
}
|
||||
|
||||
public String getIgnoreSqls() {
|
||||
return ignoreSqls;
|
||||
}
|
||||
|
||||
public void setIgnoreSqls(String ignoreSqls) {
|
||||
this.ignoreSqls = ignoreSqls;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
package com.tiesheng.database.service;
|
||||
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import cn.hutool.core.lang.func.VoidFunc1;
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.db.Db;
|
||||
import cn.hutool.db.Entity;
|
||||
import com.tiesheng.database.config.DbMigrationConfig;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.web.servlet.ServletContextInitializer;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.sql.DataSource;
|
||||
import java.io.InputStream;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
import java.util.zip.Checksum;
|
||||
|
||||
/**
|
||||
* 数据库表版本对比
|
||||
*
|
||||
* @author hao
|
||||
*/
|
||||
@Component
|
||||
public class DbMigrationInitializer implements ServletContextInitializer {
|
||||
|
||||
@Autowired
|
||||
DataSource dataSource;
|
||||
@Autowired
|
||||
DbMigrationConfig dbMigrationConfig;
|
||||
|
||||
|
||||
@Override
|
||||
public void onStartup(ServletContext servletContext) {
|
||||
try {
|
||||
startDeal();
|
||||
} catch (Exception ignore) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 开始处理数据
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
private void startDeal() throws Exception {
|
||||
Db coreDb = Db.use(dataSource);
|
||||
dbMigrationConfig.checkDbExists(coreDb);
|
||||
|
||||
PathMatchingResourcePatternResolver patternResolver = new PathMatchingResourcePatternResolver();
|
||||
for (String location : dbMigrationConfig.getLocations()) {
|
||||
Resource[] resources = patternResolver.getResources(location);
|
||||
if (ArrayUtil.isEmpty(resources)) {
|
||||
return;
|
||||
}
|
||||
for (Resource resource : resources) {
|
||||
migrationByResource(resource, coreDb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 根据资源合并数据库结构
|
||||
*
|
||||
* @param resource
|
||||
* @param db
|
||||
* @throws Exception
|
||||
*/
|
||||
private void migrationByResource(Resource resource, Db db) throws Exception {
|
||||
InputStream inputStream = resource.getInputStream();
|
||||
String readUtf8 = IoUtil.readUtf8(inputStream);
|
||||
String filename = resource.getFilename();
|
||||
Checksum checksum = IoUtil.checksum(resource.getInputStream(), null);
|
||||
Entity entity = fileChecksum(db, filename, checksum.getValue());
|
||||
if (entity == null) {
|
||||
return;
|
||||
}
|
||||
db.tx((VoidFunc1<Db>) parameter -> {
|
||||
List<String> split = StrUtil.split(readUtf8, ";");
|
||||
for (String sql : split) {
|
||||
sql = sql.trim();
|
||||
if (StrUtil.isEmpty(sql)) {
|
||||
continue;
|
||||
}
|
||||
if (StrUtil.containsAnyIgnoreCase(sql, StrUtil.splitToArray(dbMigrationConfig.getIgnoreSqls(), ","))) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
parameter.execute(sql);
|
||||
} catch (Exception ignore) {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
entity.set("checksum", checksum.getValue());
|
||||
entity.set("update_time", DateUtil.date());
|
||||
db.update(entity, Entity.create(dbMigrationConfig.getTable()).set("id", entity.get("id")));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 检查文件是否执行
|
||||
*
|
||||
* @param db
|
||||
* @param fileName
|
||||
* @param checksum
|
||||
*/
|
||||
private Entity fileChecksum(Db db, String fileName, long checksum) throws SQLException {
|
||||
Entity entity = db.get(dbMigrationConfig.getTable(), "file", fileName);
|
||||
if (entity == null) {
|
||||
entity = new Entity(dbMigrationConfig.getTable());
|
||||
entity.set("id", IdUtil.getSnowflakeNextId());
|
||||
entity.set("create_time", DateUtil.date());
|
||||
entity.set("update_time", DateUtil.date());
|
||||
entity.set("is_deleted", 0);
|
||||
entity.set("file", fileName);
|
||||
entity.set("checksum", 0);
|
||||
db.insert(entity);
|
||||
}
|
||||
|
||||
if (entity.getLong("checksum") != checksum) {
|
||||
return entity;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user