2 Star 2 Fork 2

铁猛 / go_mysqlbinlog2sql

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
binlog2sql.go 8.85 KB
一键复制 编辑 原始数据 按行查看 历史
package main
import (
"database/sql"
"flag"
"fmt"
_ "github.com/go-sql-driver/mysql"
"io/ioutil"
"os"
"os/exec"
"regexp"
"strconv"
"strings"
"sync"
)
var DB *sql.DB
var err error
func InitDB(userName string, password string, ip string, port string, dbName string) error {
//构建连接:"用户名:密码@tcp(IP:端口)/数据库?charset=utf8"
path := strings.Join([]string{userName, ":", password, "@tcp(", ip, ":", port, ")/", dbName, "?charset=utf8"}, "")
//打开数据库,前者是驱动名,所以要导入: _ "github.com/go-sql-driver/mysql"
DB, err = sql.Open("mysql", path)
if err != nil {
return err
}
//设置数据库最大连接数
DB.SetConnMaxLifetime(100)
//设置上数据库最大闲置连接数
DB.SetMaxIdleConns(10)
//验证连接
if err := DB.Ping(); err != nil {
return err
}
return nil
}
func getFields(tablename string, dbname string) []string {
var a []string
rows, err := DB.Query("SELECT COLUMN_NAME FROM COLUMNS WHERE TABLE_NAME = ? and TABLE_SCHEMA=?", tablename, dbname)
if err != nil {
fmt.Println("查询出错了")
}
for rows.Next() {
var feild string
rows.Scan(&feild)
a = append(a, feild)
}
return a
}
func getBinLogPath() string {
var BinLogPath string
var Name string
err = DB.QueryRow("SHOW VARIABLES LIKE \"log_bin_basename\"").Scan(&Name, &BinLogPath)
if err != nil {
panic(err)
}
BinLogPath = BinLogPath[0 : strings.LastIndex(BinLogPath, "/")+1]
return BinLogPath
}
func ExecCommand(strCommand string) (string, error) {
cmd := exec.Command("/bin/bash", "-c", strCommand)
stdout, _ := cmd.StdoutPipe()
if err := cmd.Start(); err != nil {
fmt.Println("Execute failed when Start:" + err.Error())
return "", err
}
out_bytes, _ := ioutil.ReadAll(stdout)
stdout.Close()
if err := cmd.Wait(); err != nil {
fmt.Println("Execute failed when Wait:" + err.Error())
return "", err
}
return string(out_bytes), nil
}
func writeFile(data string, f os.File, f1 os.File, reg string, flag string) {
dataReg := regexp.MustCompile(reg)
dataArr := dataReg.FindAllString(data, -1)
fmt.Println(flag + " 正在处理中......")
var sqlSentence string
var s1 string
for index, v := range dataArr {
if flag == "insert" || flag == "delete" {
if flag == "insert" {
sqlSentence = strings.Replace(v, "\n### SET\n", " SET ", -1)
} else {
sqlSentence = strings.Replace(v, "\n### WHERE\n", " WHERE ", -1)
}
sqlSentence = strings.Replace(sqlSentence, "###", "", -1)
sqlSentence = strings.Replace(sqlSentence, "# at", "", -1)
if flag == "insert" {
sqlSentence = strings.Replace(sqlSentence, "\n", ",", -1)
sqlSentence = strings.Replace(sqlSentence, ", INSERT INTO", "; INSERT INTO", -1)
} else {
sqlSentence = strings.Replace(sqlSentence, "\n", " AND ", -1)
sqlSentence = strings.Replace(sqlSentence, "AND DELETE FROM", "; DELETE FROM", -1)
sqlSentence = sqlSentence[0 : len(sqlSentence)-4]
}
sqlSentence = regexp.MustCompile(`\s+`).ReplaceAllString(sqlSentence, " ")
//sqlSentence = strings.Replace(v, "DELETE FROM", "\nDELETE FROM", -1)
sqlSentence = sqlSentence[0 : len(sqlSentence)-1]
t := regexp.MustCompile("(`\\w+`\\.`\\w+`*?)")
dbTable := strings.Replace(string(t.Find([]byte(sqlSentence))), "`", "", -1)
db := strings.Split(dbTable, ".")[0]
table := strings.Split(dbTable, ".")[1]
arr := getFields(table, db)
length := len(arr)
if length <= 0 {
continue
}
for k, _ := range arr {
sqlSentence = strings.Replace(sqlSentence, "@"+strconv.Itoa(length-k), arr[length-k-1], -1)
}
if flag == "delete" {
s1 = strings.Replace(sqlSentence, "DELETE FROM", "INSERT INTO", -1)
s1 = strings.Replace(s1, "WHERE", "SET", -1)
s1 = strings.Replace(s1, "AND", ",", -1)
//sqlSentence += "\nDELETE反向解析后的sql==========\n" + s1 + "\n=============\n"
} else {
s1 = strings.Replace(sqlSentence, "INSERT INTO", "DELETE FROM", -1)
s1 = strings.Replace(s1, "SET", "WHERE", -1)
s1 = strings.Replace(s1, ",", " AND", -1)
//sqlSentence += "\nINSERT反向解析后的sql==========\n" + s1 + "\n=============\n"
}
} else if flag == "update" {
sqlSentence = strings.Replace(v, "###", "", -1)
sqlSentence = strings.Replace(sqlSentence, "# at", "", -1)
sqlSentence = strings.Replace(sqlSentence, "/*!*/;", "", -1)
where := regexp.MustCompile("\\s+").ReplaceAllString(strings.Replace(strings.Replace(sqlSentence[strings.LastIndex(sqlSentence, "WHERE"):strings.LastIndex(sqlSentence, "SET")], "WHERE\n", "WHERE", -1), "\n", " AND", -1), " ")
where = where[0 : len(where)-4]
where1 := regexp.MustCompile("\\s+").ReplaceAllString(strings.Replace(strings.Replace(sqlSentence[strings.LastIndex(sqlSentence, "WHERE"):strings.LastIndex(sqlSentence, "SET")], "WHERE\n", "SET", -1), "\n", " ,", -1), " ")
where1 = where1[0 : len(where1)-2]
upTable := sqlSentence[0:strings.LastIndex(sqlSentence, "WHERE")]
set := regexp.MustCompile("\\s+").ReplaceAllString(strings.Replace(strings.Replace(sqlSentence[strings.LastIndex(sqlSentence, "SET"):], "SET\n", "SET", -1), "\n", ",", -1), " ")
set = set[0 : len(set)-1]
set1 := regexp.MustCompile("\\s+").ReplaceAllString(strings.Replace(strings.Replace(sqlSentence[strings.LastIndex(sqlSentence, "SET"):], "SET\n", "WHERE", -1), "\n", " AND", -1), " ")
set1 = set1[0 : len(set1)-4]
sqlSentence = upTable + " " + set + " " + where
s1 = upTable + " " + where1 + " " + set1
t := regexp.MustCompile("`.+`\\.`.+`*?")
dbTable1 := strings.Replace(string(t.Find([]byte(sqlSentence))), "`", "", -1)
db1 := strings.Split(dbTable1, ".")[0]
table1 := strings.Split(dbTable1, ".")[1]
arr := getFields(table1, db1)
lenth := len(arr)
if lenth <= 0 {
continue
}
for k1, _ := range arr {
sqlSentence = strings.Replace(sqlSentence, "@"+strconv.Itoa(lenth-k1), arr[lenth-k1-1], -1)
s1 = strings.Replace(s1, "@"+strconv.Itoa(lenth-k1), arr[lenth-k1-1], -1)
}
} else if flag == "create" {
sqlSentence = strings.Replace(v, "/*!*/;", "", -1)
s1 = ""
} else {
sqlSentence = strings.Replace(v, "\n", "", -1)
sqlSentence = strings.Replace(sqlSentence, "/*!*/;", ";", -1)
s1 = ""
}
f1.WriteString("(" + flag + strconv.Itoa(index+1) + ")\t" + s1)
f1.WriteString("\n")
f.WriteString("(" + flag + strconv.Itoa(index+1) + ")\t" + sqlSentence)
f.WriteString("\n")
}
wg.Done()
}
var wg sync.WaitGroup
func main() {
var binLogPath string
var binLogName string
var mysqlHost string
var mysqlPort string
var mysqlUser string
var mysqlPass string
var saveFile string
var start string
var end string
var startDate string
var endDate string
flag.StringVar(&binLogName, "bin-log-name", "", "--bin-log-name bin-log文件名称")
flag.StringVar(&mysqlPort, "P", "3306", "-P 数据库端口号")
flag.StringVar(&mysqlHost, "h", "127.0.0.1", "-h 数据库IP")
flag.StringVar(&mysqlUser, "u", "root", "-u 数据库用户名")
flag.StringVar(&mysqlPass, "p", "123456", "-p 数据库密码")
flag.StringVar(&saveFile, "save-path", "./bin2sql.sql", "-save-path 保存解析后的文件")
flag.StringVar(&start, "start", "", "--start-position 开始位置")
flag.StringVar(&end, "end", "", "--end-position 结束位置")
flag.StringVar(&startDate, "start-date", "", "--start-date 结束位置")
flag.StringVar(&endDate, "end-date", "", "--end-date 结束位置")
flag.Parse()
var command = "mysqlbinlog -v --base64-output=decode-rows "
if binLogName == "" {
fmt.Println("请输入binlog文件名")
os.Exit(-1)
}
connectStatus := InitDB(mysqlUser, mysqlPass, mysqlHost, mysqlPort, "information_schema")
if connectStatus != nil {
fmt.Println(connectStatus)
os.Exit(-3)
}
binLogPath = getBinLogPath() + binLogName
if start != "" {
command += " --start-position=" + start
}
if end != "" {
command += " --end-position=" + end
}
if startDate != "" {
command += " --start-datetime='" + startDate + "'"
}
if endDate != "" {
command += " --stop-datetime='" + endDate + "'"
}
command += " " + binLogPath
fmt.Println("执行命令为:" + command)
//os.Exit(-1)
if _, err := os.Stat(binLogPath); os.IsNotExist(err) {
fmt.Println(binLogPath + ":文件不存在")
os.Exit(-2)
}
strData, err1 := ExecCommand(command)
if err1 != nil {
fmt.Println(err1)
os.Exit(-4)
}
f, err := os.Create(saveFile)
f1, err1 := os.Create("./tun.sql")
defer f.Close()
defer f1.Close()
if err != nil {
fmt.Println(err)
}
if err1 != nil {
fmt.Println(err1)
}
sqlArr := map[string]string{
"create": `(?msi:CREATE TABLE [a-z]+[a-z].*?/*!*/;)+`,
"insert": `(?msi:INSERT [a-z]+[a-z].*?# at)+`,
"delete": `(?msi:DELETE [a-z]+[a-z].*?# at)+`,
"update": "(?msi:UPDATE `.[a-z].*?# at)+",
"alter": `(?msi:ALTER [a-z]+((\s+))[a-z].*?/*!*/;)+`,
}
for k, v := range sqlArr {
wg.Add(1)
go writeFile(strData, *f, *f1, v, k)
}
wg.Wait()
fmt.Println("解析完成,binlog解析sql保存文件为:" + saveFile)
fmt.Println("\t 反解析后的文件保存为::./tun.sql")
}
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
Go
1
https://gitee.com/tmpgms/go_mysqlbinlog2sql.git
git@gitee.com:tmpgms/go_mysqlbinlog2sql.git
tmpgms
go_mysqlbinlog2sql
go_mysqlbinlog2sql
master

搜索帮助

344bd9b3 5694891 D2dac590 5694891