以往java备份mysql数据库需要通过dump工具,不同的服务器需要配置环境变量来实现,不具通用性,能不能使用纯java代码来实现呢?当然可以,先看一下如何使用,以jfinal为例子:PropKit.use("config.txt");
MySqlInfo mySqlInfo = new MySqlInfo(PropKit.get("jdbcUrl"), PropKit.get("user"), PropKit.get("password"));
MysqlExport mysqlExport = new MysqlExport(mySqlInfo);
try {
mysqlExport.export();
} catch (IOException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
以上代码是从配置文件中读取mysql的配置信息jdbcUrl,user,password,然后封装到MySqlInfo里.
MySqlInfo的代码:public class MySqlInfo {
private String jdbcUrl="";
private String user="";
private String password="";
private String exportPath= "dbbak";
public String getExportPath() {
return PathKit.getWebRootPath()+"/"+exportPath;
}
public void setExportPath(String exportPath) {
this.exportPath = exportPath;
}
public MySqlInfo(String jdbcUrl, String user, String password) {
this.jdbcUrl = jdbcUrl;
this.user = user;
this.password = password;
}
public String getJdbcUrl() {
return jdbcUrl;
}
public void setJdbcUrl(String jdbcUrl) {
this.jdbcUrl = jdbcUrl;
}
public String getUser() {
return user;
}
public void setUser(String user) {
this.user = user;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
MysqlExport就是实际上的mysql导出备份类。
MysqlExport代码:import org.zeroturnaround.zip.ZipUtil;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.sql.*;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Objects;
public class MysqlExport {
private Statement stmt;
private String database;
private String generatedSql = "";
private String sqlFileName = "";
private String zipFileName = "";
private File generatedZipFile;
private MySqlInfo mySqlInfo = null;
public MysqlExport(MySqlInfo mySqlInfo) {
this.mySqlInfo = mySqlInfo;
}
/**
* 生成create语句
*
* @param table the table concerned
* @return String
* @throws SQLException exception
*/
private String getTableInsertStatement(String table) throws SQLException {
StringBuilder sql = new StringBuilder();
ResultSet rs;
boolean addIfNotExists = true;
if (table != null && !table.isEmpty()) {
rs = stmt.executeQuery("SHOW CREATE TABLE " + "`" + table + "`;");
while (rs.next()) {
String qtbl = rs.getString(1);
String query = rs.getString(2);
sql.append("\n\n--");
sql.append("\n").append(MysqlUtil.SQL_START_PATTERN).append(" table dump : ").append(qtbl);
sql.append("\n--\n\n");
if (addIfNotExists) {
query = query.trim().replace("CREATE TABLE", "CREATE TABLE IF NOT EXISTS");
}
sql.append(query).append(";\n\n");
}
sql.append("\n\n--");
sql.append("\n").append(MysqlUtil.SQL_END_PATTERN).append(" table dump : ").append(table);
sql.append("\n--\n\n");
}
return sql.toString();
}
/**
* 生成insert语句
*
* @param table the table to get inserts statement for
* @return String generated SQL insert
* @throws SQLException exception
*/
private String getDataInsertStatement(String table) throws SQLException {
StringBuilder sql = new StringBuilder();
ResultSet rs = stmt.executeQuery("SELECT * FROM " + "`" + table + "`;");
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(MysqlUtil.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
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
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);
val = val.replace("'", "\\'");
sql.append("'").append(val).append("', ");
}
}
sql.deleteCharAt(sql.length() - 1).deleteCharAt(sql.length() - 1);
if (rs.isLast()) {
sql.append(")");
} else {
sql.append("),\n");
}
}
sql.append(";");
sql.append("\n--\n")
.append(MysqlUtil.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
* @throws SQLException exception
*/
private String exportToSql() throws SQLException {
StringBuilder sql = new StringBuilder();
sql.append("--");
sql.append("\n-- Generated by workbgm");
sql.append("\n-- Date: ").append(new SimpleDateFormat("d-M-Y H:m:s").format(new Date()));
sql.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 */;")
.append("\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 tables = MysqlUtil.getAllTables(database, stmt);
for (String s : tables) {
try {
sql.append(getTableInsertStatement(s.trim()));
sql.append(getDataInsertStatement(s.trim()));
} catch (SQLException e) {
e.printStackTrace();
}
}
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 */;");
this.generatedSql = sql.toString();
return sql.toString();
}
/**
* 从jdbcUrl中提取数据库名
*
* @param jdbcUrl
* @return
*/
public String findDBName(String jdbcUrl) {
String dbName = "";
int s = jdbcUrl.lastIndexOf("/") + 1;
int e = jdbcUrl.lastIndexOf("?");
dbName = jdbcUrl.substring(s, e);
return dbName;
}
/**
* 导出入口
*
* @throws IOException exception
* @throws SQLException exception
* @throws ClassNotFoundException exception
*/
public void export() throws IOException, SQLException, ClassNotFoundException {
//connect to the database
database = findDBName(this.mySqlInfo.getJdbcUrl());
String driverName = "";
Connection connection;
connection = MysqlUtil.connectWithURL(this.mySqlInfo.getUser(),
this.mySqlInfo.getPassword(), this.mySqlInfo.getJdbcUrl(),
driverName
);
stmt = connection.createStatement();
//generate the final SQL
String sql = exportToSql();
//create a temp dir to store the exported file for processing
String dirName = this.mySqlInfo.getExportPath();
File file = new File(dirName);
if (!file.exists()) {
boolean res = file.mkdir();
if (!res) {
System.out.println("Unable to create temp dir: " + file.getAbsolutePath());
throw new IOException("Unable to create temp dir: " + file.getAbsolutePath());
}
}
//write the sql file out
File sqlFolder = new File(dirName + "/sql");
if (!sqlFolder.exists()) {
boolean res = sqlFolder.mkdir();
if (!res) {
throw new IOException(": Unable to create temp dir: " + file.getAbsolutePath());
}
}
sqlFileName = getSqlFilename();
FileOutputStream outputStream = new FileOutputStream(sqlFolder + "/" + sqlFileName);
outputStream.write(sql.getBytes());
outputStream.close();
//zip the file
zipFileName = dirName + "/" + sqlFileName.replace(".sql", ".zip");
generatedZipFile = new File(zipFileName);
ZipUtil.pack(sqlFolder, generatedZipFile);
//clear the generated temp files
clearTempFiles(true);
}
/**
* 清理临时文件
*
* @param preserveZipFile bool
*/
public void clearTempFiles(boolean preserveZipFile) {
String dirName = this.mySqlInfo.getExportPath();
//delete the temp sql file
File sqlFile = new File(dirName + "/sql/" + sqlFileName);
if (sqlFile.exists()) {
boolean res = sqlFile.delete();
System.out.println(": " + sqlFile.getAbsolutePath() + " deleted successfully? " + (res ? " TRUE " : " FALSE "));
} else {
System.out.println(": " + sqlFile.getAbsolutePath() + " DOES NOT EXIST while clearing Temp Files");
}
File sqlFolder = new File(dirName + "/sql");
if (sqlFolder.exists()) {
boolean res = sqlFolder.delete();
System.out.println(": " + sqlFolder.getAbsolutePath() + " deleted successfully? " + (res ? " TRUE " : " FALSE "));
} else {
System.out.println(": " + sqlFolder.getAbsolutePath() + " DOES NOT EXIST while clearing Temp Files");
}
if (!preserveZipFile) {
//delete the zipFile
File zipFile = new File(zipFileName);
if (zipFile.exists()) {
boolean res = zipFile.delete();
System.out.println(": " + zipFile.getAbsolutePath() + " deleted successfully? " + (res ? " TRUE " : " FALSE "));
} else {
System.out.println(": " + zipFile.getAbsolutePath() + " DOES NOT EXIST while clearing Temp Files");
}
//delete the temp folder
File folder = new File(dirName);
if (folder.exists()) {
boolean res = folder.delete();
System.out.println(": " + folder.getAbsolutePath() + " deleted successfully? " + (res ? " TRUE " : " FALSE "));
} else {
System.out.println(": " + folder.getAbsolutePath() + " DOES NOT EXIST while clearing Temp Files");
}
}
System.out.println(": generated temp files cleared successfully");
}
/**
* 生成文件名
* sql file name.
*
* @return String
*/
public String getSqlFilename() {
return new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss").format(new Date()) + "_" + database + "_database_dump.sql";
}
/**
* 获取备份的sql zip文件
*
* @return
*/
public File getGeneratedZipFile() {
if (generatedZipFile != null && generatedZipFile.exists()) {
return generatedZipFile;
}
return null;
}
}
需要注意的是MysqlExport依赖一个zip打包类ZipUtil和mysql工具类MysqlUtil.
MysqlUtil的代码:import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
public class MysqlUtil {
static final String SQL_START_PATTERN = "-- start";
static final String SQL_END_PATTERN = "-- end";
/**
* 通过jdbcurl连接数据库
* @param username database username
* @param password database password
* @param jdbcURL the user supplied JDBC URL. It's used as is. So ensure you supply the right parameters
* @param driverName the user supplied mysql connector driver class name
* @return Connection
* @throws ClassNotFoundException exception
* @throws SQLException exception
*/
static Connection connectWithURL(String username, String password, String jdbcURL, String driverName) throws ClassNotFoundException, SQLException {
String driver = (Objects.isNull(driverName) || driverName.isEmpty()) ? "com.mysql.jdbc.Driver" : driverName;
return doConnect(driver, jdbcURL, username, password);
}
/**
* 连接数据库
* @param driver the class name for the mysql driver to use
* @param url the url of the database
* @param username database username
* @param password database password
* @return Connection
* @throws SQLException exception
* @throws ClassNotFoundException exception
*/
private static Connection doConnect(String driver, String url, String username, String password) throws SQLException, ClassNotFoundException {
Class.forName(driver);
Connection connection = DriverManager.getConnection(url, username, password);
System.out.println("DB Connected Successfully");
return connection;
}
/**
* 获取所有表
* @param database the database name
* @param stmt Statement object
* @return List\
* @throws SQLException exception
*/
static List getAllTables(String database, Statement stmt) throws SQLException {
List table = new ArrayList<>();
ResultSet rs;
rs = stmt.executeQuery("SHOW TABLE STATUS FROM `" + database + "`;");
while ( rs.next() ) {
table.add(rs.getString("Name"));
}
return table;
}
}
ZipUtil需要用maven引入一下:
org.zeroturnaround
zt-zip
1.12
jar