1. 直接導入數據庫
mysqlbinlog --database=testdb mysql-bin.000001 | mysql -uroot -f
2. 導出成SQL文
(1) 從binlog輸出為SQL
mysqlbinlog -vv --database=testdb --base64-output=decode-rows mysql-bin.000001 > 0001.sql grep "###" 0001.sql > 0001_#.sql
導出的SQL文如下格式:
### UPDATE `test`.`test_data1` ### WHERE ### @1='2002001809730903086' /* VARSTRING(150) meta=150 nullable=0 is_null=0 */ ### @2='2001001959581442003' /* VARSTRING(150) meta=150 nullable=0 is_null=0 */ ### @3='0661594' /* VARSTRING(150) meta=150 nullable=1 is_null=0 */ ### @4='758686' /* VARSTRING(150) meta=150 nullable=1 is_null=0 */ ### @5=1449174648065 /* LONGINT meta=0 nullable=1 is_null=0 */ ### @6=0 /* LONGINT meta=0 nullable=1 is_null=0 */ ### @7=0 /* LONGINT meta=0 nullable=1 is_null=0 */ ### @8=0 /* LONGINT meta=0 nullable=1 is_null=0 */ ### @9=1458787027688 /* LONGINT meta=0 nullable=1 is_null=0 */ ### @10=0 /* LONGINT meta=0 nullable=1 is_null=0 */ ### @11=1458787027688 /* LONGINT meta=0 nullable=1 is_null=0 */ ### @12=300 /* INT meta=0 nullable=1 is_null=0 */ ### SET ### @1='2002001809730903086' /* VARSTRING(150) meta=150 nullable=0 is_null=0 */ ### @2='2001001959581442003' /* VARSTRING(150) meta=150 nullable=0 is_null=0 */ ### @3='0661594' /* VARSTRING(150) meta=150 nullable=1 is_null=0 */ ### @4='758686' /* VARSTRING(150) meta=150 nullable=1 is_null=0 */ ### @5=1449174648065 /* LONGINT meta=0 nullable=1 is_null=0 */ ### @6=0 /* LONGINT meta=0 nullable=1 is_null=0 */ ### @7=0 /* LONGINT meta=0 nullable=1 is_null=0 */ ### @8=0 /* LONGINT meta=0 nullable=1 is_null=0 */ ### @9=1458787027688 /* LONGINT meta=0 nullable=1 is_null=0 */ ### @10=1458787191658 /* LONGINT meta=0 nullable=1 is_null=0 */ ### @11=1458787191658 /* LONGINT meta=0 nullable=1 is_null=0 */ ### @12=400 /* INT meta=0 nullable=1 is_null=0 */ ### INSERT INTO `test`.`test_data2` ### SET ### @1='00020017b4c3418b' /* VARSTRING(48) meta=48 nullable=0 is_null=0 */ ### @2='2002001809730903086' /* VARSTRING(150) meta=150 nullable=0 is_null=0 */ ### @3='00003997' /* VARSTRING(150) meta=150 nullable=1 is_null=0 */ ### @4='0661594' /* VARSTRING(150) meta=150 nullable=1 is_null=0 */ ### @5=1458787191658 /* LONGINT meta=0 nullable=1 is_null=0 */ ### @6=0 /* INT meta=0 nullable=1 is_null=0 */
(2) 需要將其轉換可以在mysql客戶端執行的SQL。我寫了一個小程序處理這個格式,代碼如下:
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
/**
*
* @author Beef Liu
*
**/
public class BinLogSQLConverter {
public final static String RTN_LINE = "\r\n";
private final static String SQL_WORD_INSERT_INTO = "INSERT INTO";
private final static String SQL_WORD_UPDATE = "UPDATE";
private final static String SQL_WORD_DELETE = "DELETE";
private final static String SQL_WORD_SET = "SET";
private final static String SQL_WORD_WHERE = "WHERE";
private final static String LINE_COMMENT = "###";
private final static String REGEX_BLOCK_COMMENT = "/\\*[^\\n']*/";
public static class TableDesc {
private String _tableName;
private String[] _colNames;
public TableDesc() {
}
public TableDesc(String tableName, String[] colNames) {
_tableName = tableName;
_colNames = colNames;
}
public String getTableName() {
return _tableName;
}
public void setTableName(String tableName) {
_tableName = tableName;
}
public String[] getColNames() {
return _colNames;
}
public void setColNames(String[] colNames) {
_colNames = colNames;
}
}
public static void convertToSQL(
File inputBinSQL, File outputSQL,
Charset charset,
TableDesc[] tableDescs
) throws IOException {
BufferedReader reader = new BufferedReader(
new InputStreamReader(new FileInputStream(inputBinSQL), charset));
try {
OutputStreamWriter writer = new OutputStreamWriter(
new BufferedOutputStream(new FileOutputStream(outputSQL)),
charset);
try {
List<String> lines = new ArrayList<String>();
while(true) {
String line = reader.readLine();
if(line == null) {
break;
}
//trim '###'
if(line.startsWith(LINE_COMMENT)) {
line = line.substring(LINE_COMMENT.length());
}
//trim block comment
line = line.replaceAll(REGEX_BLOCK_COMMENT, "");
if(startsWithAndIgnoreSpace(line, SQL_WORD_INSERT_INTO)
|| startsWithAndIgnoreSpace(line, SQL_WORD_UPDATE)
|| startsWithAndIgnoreSpace(line, SQL_WORD_DELETE)
) {
//format previous statement
if(lines.size() > 0) {
String formatedStmt = formatStatement(tableDescs, lines);
if(formatedStmt != null && formatedStmt.length() > 0) {
writer.append(formatedStmt).append(RTN_LINE);
}
}
//new statement
lines.clear();
}
lines.add(line);
}
if(lines.size() > 0) {
String formatedStmt = formatStatement(tableDescs, lines);
if(formatedStmt != null && formatedStmt.length() > 0) {
writer.append(formatedStmt).append(RTN_LINE);
}
}
} finally {
writer.close();
}
} finally {
reader.close();
}
}
private final static String formatStatement(TableDesc[] tableDescs, List<String> lines) {
String line;
line = lines.get(0);
if(startsWithAndIgnoreSpace(line, SQL_WORD_INSERT_INTO)) {
return formatStatementOfInsert(tableDescs, lines);
} else if (startsWithAndIgnoreSpace(line, SQL_WORD_UPDATE)) {
return formatStatementOfUpdate(tableDescs, lines);
} else {
System.out.println("Not supported yet. statement type:" + line);
return "";
}
}
private final static String formatStatementOfInsert(TableDesc[] tableDescs, List<String> lines) {
/*
INSERT INTO `test`.`test_data1`
SET
@1='00020017bae7830b'
@2='2002001280299806243'
@3='00004407'
@4='0661601'
@5=1458889871654
@6=0
*/
String tableName = findTableNameInLine(lines.get(0));
TableDesc tblDesc = getTableDesc(tableDescs, tableName);
if(tblDesc == null) {
return null;
}
StringBuilder sql = new StringBuilder();
//INSERT INTO
sql.append(lines.get(0)).append(RTN_LINE);
//SET
sql.append(lines.get(1)).append(RTN_LINE);
//@1=xxxx
for(int i = 2; i < lines.size(); i++) {
if (i > 2) {
sql.append(", ");
}
sql.append(substituteColName(tblDesc, lines.get(i))).append(RTN_LINE);
}
sql.append(";").append(RTN_LINE);
return sql.toString();
}
private final static String formatStatementOfUpdate(TableDesc[] tableDescs, List<String> lines) {
/*
UPDATE `test`.`test_data2`
WHERE
@1='2002001280299806243'
@2='2001001394921721184'
@3='0661601'
@4='758029'
@5=1450922125360
@6=0
@7=1458889670699
@8=0
@9=1458889682247
@10=0
@11=1458889682247
@12=300
SET
@1='2002001280299806243'
@2='2001001394921721184'
@3='0661601'
@4='758029'
@5=1450922125360
@6=0
@7=1458889670699
@8=0
@9=1458889682247
@10=1458889871654
@11=1458889871654
@12=400
*/
String tableName = findTableNameInLine(lines.get(0));
TableDesc tblDesc = getTableDesc(tableDescs, tableName);
if(tblDesc == null) {
return null;
}
StringBuilder sql = new StringBuilder();
//UPDATE
sql.append(lines.get(0)).append(RTN_LINE);
List<String> blockOfWhere = new ArrayList<String>();
List<String> blockOfSet = new ArrayList<String>();
//@1=xxxx
List<String> blockRef = blockOfWhere;
for(int i = 1; i < lines.size(); i++) {
String line = lines.get(i);
if(startsWithAndIgnoreSpace(line, SQL_WORD_SET)) {
blockRef = blockOfSet;
}
line = substituteColName(tblDesc, line);
blockRef.add(line);
}
//output SET block
sql.append(blockOfSet.get(0)).append(RTN_LINE);
for(int i = 1; i < blockOfSet.size(); i++) {
if(i > 1) {
sql.append(", ");
}
sql.append(blockOfSet.get(i)).append(RTN_LINE);
}
sql.append(blockOfWhere.get(0)).append(RTN_LINE);
for(int i = 1; i < blockOfWhere.size(); i++) {
if (i > 1) {
sql.append("AND ");
}
sql.append(blockOfSet.get(i)).append(RTN_LINE);
}
sql.append(";").append(RTN_LINE);
return sql.toString();
}
private final static String substituteColName(
TableDesc tblDesc, String line) {
int index0 = line.indexOf('@');
if(index0 < 0) {
return line;
}
int index1 = line.indexOf('=', index0);
if(index1 < 0) {
return line;
}
int colNum = Integer.parseInt(line.substring(index0 + 1, index1));
return line.substring(0, index0)
.concat("`").concat(tblDesc.getColNames()[colNum - 1]).concat("`")
.concat(line.substring(index1))
;
}
private final static String findTableNameInLine(String line) {
int index1 = line.lastIndexOf('`');
int index0 = line.lastIndexOf('`', index1 - 1);
return line.substring(index0 + 1, index1);
}
private final static TableDesc getTableDesc(TableDesc[] tableDescs, String tableName) {
for(TableDesc desc : tableDescs) {
if(desc.getTableName().equalsIgnoreCase(tableName)) {
return desc;
}
}
return null;
}
private final static boolean startsWithAndIgnoreSpace(String str, String prefix) {
int begin;
for(begin = 0; begin < str.length(); begin++) {
char c = str.charAt(begin);
if(c != ' ') {
break;
}
}
return str.startsWith(prefix, begin);
}
}
調用的例子:
@Test
public void test1() {
try {
File input = new File("test/restore001_#.sql");
File output = new File("test/restore001_#formated.sql");
BinLogSQLConverter.convertToSQL(
input, output,
Charset.forName("utf-8"),
new BinLogSQLConverter.TableDesc[] {
new BinLogSQLConverter.TableDesc(
"test_data1",
new String[] {"code","name","col3","col4"}
),
new BinLogSQLConverter.TableDesc(
"test_data2",
new String[] {"code","name","col3","col4"}
),
}
);
} catch (Throwable e) {
e.printStackTrace();
}
}