视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
golang实现mysql数据库备份的操作方法
2020-11-09 20:25:58 责编:小采
文档


背景

navicat是mysql可视化工具中最棒的,但是,在处理视图的导入导出方面,它是按照视图名称的字母顺序来处理的,若视图存在依赖,在导入过程中就会报错。前面已经用python写了一个,但在使用过程中,遇到xfffd编码,python的pymysql会直接崩溃。发现golang没有这个问题,正好用go重写,来熟悉golang。

一些关键点

  1. map & json,在处理主键与外键信息时,需要用到json数据结构来存储中间结果,因为要灵活处理,在golang中只能用map[string]interface{}来处理。
  2. interface{} 相当于java中的object,能接受任意数据类型,方便但在使用时要做到心中有数,不然一旦数据类型不匹配,程序就会崩溃。
  3. xfffd ,utf8中的占位符,超出范围的utf8mb4入库后,会被存储为xfffd,数据导出时,需要过滤掉。
  4. goroutine, golang的并发支持很独特,我们的工具支持多个库同时备份,很容易使用goroutine来实现并行。

代码解析

按功能模块对核心代码进行说明

main.go,并发、命令行参数

使用命令行参数,接受一个参数,来指定备份的内容

package common

type OpFlag struct {
 Tables bool //表结构
 Datum bool //表结构和数据
 Views bool //视图
 Funcs bool //函数与存储过程
}

main.go,程序入口,处理命令行参数  

 if len(os.Args) > 1 {
 flag = common.OpFlag{
 Tables: false,
 Datum: false,
 Views: false,
 Funcs: false,
 }
 switch os.Args[1] { //接受一个参数
 case "table":
 flag.Tables = true //根据参数设定标识量
 case "data":
 flag.Tables = true
 flag.Datum = true
 case "views":
 flag.Views = true
 case "funcs":
 flag.Funcs = true
 default: //参数不正确,报错退出
 log.Fatal("You arg must be in : table, data, views or funcs.")
 }
 }else{ //无参数,默认导出所有
 flag = common.OpFlag{
 Tables: true,
 Datum: true,
 Views: true,
 Funcs: true,
 }
 }
 err := backUp.Export(flag) 根据参数进行数据库备份

Export.go

备份主流程,根据configs.json生成goroutine来备份数据库,并等待完成。

var configs interface{}
 fr, err := os.Open("./configs.json")
 if err != nil {
 return err
 }
 decoder := json.NewDecoder(fr) //解析配置文件
 err = decoder.Decode(&configs)
 confs := configs.(map[string]interface{})
 workDir := confs["workDir"].(string)
 ch := make(chan string) //通道变量
 for key, value := range confs {
 if strings.HasPrefix(key, "db_") {
 dbConf := value.(map[string]interface{})
 dbConn := common.DbConnFields{ //数据库相应配置
 DbHost: dbConf["db_host"].(string),
 DbPort: int(dbConf["db_port"].(float)),
 DbUser: dbConf["db_user"].(string),
 DbPass: dbConf["db_pass"].(string),
 DbName: dbConf["db_name"].(string),
 DbCharset: dbConf["db_charset"].(string),
 }
 if dbConf["file_alias"] != nil { //生成sql备份文件的命名
 dbConn.FileAlias = dbConf["file_alias"].(string)
 }
 go ExportOne(dbConn, workDir, ch, flag) //创建协程
 }
 }
 for key := range confs { //阻塞主进程,待所有协程完成工作
 if strings.HasPrefix(key, "db_") {
 fmt.Print( <- ch )
 }
 }
 return nil

你需要编写如下的配置文件来描述你要备份的数据库:

{
 "db_name1": {
 "db_host": "192.168.1.8",
 "db_port": 3306,
 "db_user": "root",
 "db_pass": "123456",
 "db_name": "name1",
 "db_charset": "utf8mb4",
 "file_alias": "file name1"
 },
 "db_name2": {
 "db_host": "localhost",
 "db_port": 3306,
 "db_user": "root",
 "db_pass": "123456",
 "db_name": "name2",
 "db_charset": "utf8mb4"
 },
 "database_dialect": "mysql",
 "workDir": "/home/zhoutk/gocodes/goTools/"
}

ExportOne.go

备份一个数据库      

fileName := fields.FileAlias
 setSqlHeader(fields, fileName) //设置导出文件说明
 if flag.Tables { //如果表设置为真,导出表结构
 err := exportTables(fileName, fields, flag) //具体算法请参照源代码
 if err != nil {
 ch <- fmt.Sprintln("Error: ", fields.DbName, "\t export tables throw, \t", err)
 return
 }
 }
 if flag.Views { //如果视图设置为真,导出视图
 err := exportViews(fileName, fields)//具体算法请参照源代码,或python算法
 if err != nil {
 ch <- fmt.Sprintln("Error: ", fields.DbName, "\t export views throw, \t", err)
 return
 }
 }
 if flag.Funcs { //如果函数设置为真,导出函数和存储过程
 err := exportFuncs(fileName, fields)//具体算法请参照源代码
 if err != nil {
 ch <- fmt.Sprintln("Error: ", fields.DbName, "\t export funcs throw, \t", err)
 return
 }
 }
 //导出工作完成,向通道输入信息
 ch <- fmt.Sprintln("Export ", fields.DbName, "\t success at \t", time.Now().Format("2006-01-02 15:04:05")) 

MysqlDao.go

数据库查询通用封装,此工具只使用了ExecuteWithDbConn。灵活的使用map与interface{},将结果转化为键值对象返回。

func ExecuteWithDbConn(sql string, values []interface{}, fields common.DbConnFields) (map[string]interface{}, error) {
 rs := make(map[string]interface{})
 dao, err := mysql.Open("mysql", fields.DbUser + ":"+fields.DbPass+"@tcp("+fields.DbHost+":"+
 strconv.Itoa(fields.DbPort)+")/"+fields.DbName+"?charset="+fields.DbCharset)
 defer dao.Close()
 if err != nil {
 rs["code"] = 204
 return rs, err
 }
 stmt, err := dao.Prepare(sql)
 if err != nil {
 rs["code"] = 204
 return rs, err
 }
 rows, err := stmt.Query(values...)
 if err != nil {
 rs["code"] = 204
 return rs, err
 }
 columns, err := rows.Columns() //取出字段名称
 vs := make([]mysql.RawBytes, len(columns))
 scans := make([]interface{}, len(columns))
 for i := range vs { //预设取值地址
 scans[i] = &vs[i]
 }
 var result []map[string]interface{}
 for rows.Next() {
 _ = rows.Scan(scans...) //塡入一列值
 each := make(map[string]interface{})
 for i, col := range vs {
 if col != nil {
 each[columns[i]] = FilterHolder(string(col)) //过滤/xfffd
 }else{
 each[columns[i]] = nil
 }
 }
 result = append(result, each)
 }
 rs["code"] = 200
 //data, _ := json.Marshal(result)
 rs["rows"] = result
 return rs, err
}

项目地址

https://github.com/zhoutk/goTools

使用方法

git clone https://github.com/zhoutk/goTools
cd goTools
go get
go run main.go
go buid main.go
./main #export all things of database
./main table #export tables
./main data #export tables & data
./main views #export views
./main funcs #export funcs & stored procedures

总结

以上所述是小编给大家介绍的golang实现mysql数据库备份的操作方法,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对脚本之家网站的支持!

您可能感兴趣的文章:

  • Go语言操作mysql数据库简单例子
  • Go语言使用MySql的方法
  • Go语言中http和mysql的实现代码
  • Golang中如何对MySQL进行操作详解
  • golang gorm 操作mysql及gorm基本用法
  • 在golang中操作mysql数据库的实现代码
  • Go语言集成mysql驱动、调用数据库、查询数据操作示例
  • 下载本文
    显示全文
    专题