You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
292 lines
7.2 KiB
292 lines
7.2 KiB
package utils
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"log"
|
|
"os"
|
|
"reflect"
|
|
"regexp"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/mholt/archiver"
|
|
)
|
|
|
|
// Export 导出数据库所有表
|
|
func (md *Mysqldump) Export() (outFile string, err error) {
|
|
if md.isClose == true {
|
|
return "", errors.New("已调用Close关闭相关资源,无法进行导出")
|
|
}
|
|
// 创建导出sql文件
|
|
outFile = fmt.Sprintf("%s/%s_%s.sql", strings.TrimRight(md.cfg.OutPath, "/"), md.cfg.DbCfg.DbName, time.Now().Format("20060102T150405"))
|
|
lf, err := os.OpenFile(outFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0660)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
defer func() {
|
|
// 关闭文件
|
|
lf.Close()
|
|
// 压缩文件
|
|
if md.cfg.OutZip == true {
|
|
outZipFile := fmt.Sprintf("%s/%s_%s.zip", strings.TrimRight(md.cfg.OutPath, "/"), md.cfg.DbCfg.DbName, time.Now().Format("20060102T150405"))
|
|
err = archiver.Zip.Make(outZipFile, []string{outFile})
|
|
if err == nil {
|
|
outFile = outZipFile
|
|
}
|
|
}
|
|
}()
|
|
|
|
// 获取建库语句
|
|
createSQL, err := md.GetCreateDbSQL()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
// 获取数据库字符集
|
|
charSet := "utf8"
|
|
var valid = regexp.MustCompile("CHARACTER SET ([a-z0-9A-Z]+) ")
|
|
finds := valid.FindAllStringSubmatch(createSQL, -1)
|
|
if len(finds) > 0 {
|
|
if len(finds[0]) > 1 {
|
|
charSet = finds[0][1]
|
|
}
|
|
}
|
|
// 判断是否需要建库语句
|
|
if md.cfg.IsCreateDB == true {
|
|
createSQL = fmt.Sprintf("CREATE DATABASE `%s`; /*!40100 DEFAULT CHARACTER SET %s */", md.cfg.DbCfg.DbName, charSet)
|
|
} else {
|
|
createSQL = ""
|
|
}
|
|
|
|
// 写入头部信息
|
|
_, err = lf.WriteString(fmt.Sprintf(`/*
|
|
中防电信sql导出
|
|
|
|
数据库地址 : %s:%d
|
|
数据库类型 : MySQL
|
|
数据库名 : %s
|
|
|
|
生成时间: %s
|
|
*/
|
|
|
|
%s
|
|
|
|
SET NAMES %s;
|
|
SET FOREIGN_KEY_CHECKS = 0;
|
|
|
|
`,
|
|
md.cfg.DbCfg.Address,
|
|
md.cfg.DbCfg.Port,
|
|
md.cfg.DbCfg.DbName,
|
|
time.Now().Format("2006-01-02 15:04:05"),
|
|
createSQL,
|
|
charSet))
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
// 查询数据库表列表
|
|
tables, err := md.SelectTableNames()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
// 导出数据对象
|
|
tplSqlModel := make([]*TPLSqlModel, 0)
|
|
// 循环表名,查询出对应的表创建语句
|
|
for _, table := range tables {
|
|
log.Println("导出", table)
|
|
// 导出建表语句
|
|
sql, err := md.GetCreateTableSQL(table)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
tplSqlModel = append(tplSqlModel, &TPLSqlModel{
|
|
TableName: table,
|
|
CreateSQL: sql,
|
|
})
|
|
log.Println(sql)
|
|
// 写入一个表到建表语句
|
|
_, err = lf.WriteString(fmt.Sprintf(
|
|
`%s-- ----------------------------
|
|
-- Table structure for %s
|
|
-- ----------------------------
|
|
DROP TABLE IF EXISTS %s%s%s;
|
|
%s;
|
|
%s`,
|
|
"\n\n",
|
|
table,
|
|
"`",
|
|
table,
|
|
"`",
|
|
sql,
|
|
"\n"))
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
// 导出数据
|
|
if md.cfg.IsExportData == true {
|
|
md.ExportData(lf, table)
|
|
}
|
|
}
|
|
// js, _ := json.Marshal(aa)
|
|
// log.Println(string(js))
|
|
return outFile, nil
|
|
}
|
|
|
|
// SelectTableNames 查询数据库表列表
|
|
func (md *Mysqldump) SelectTableNames() (tables []string, err error) {
|
|
tables = make([]string, 0)
|
|
err = md.conn.SQL("SHOW TABLES;").Cols(fmt.Sprintf("Tables_in_%s", md.cfg.DbCfg.DbName)).Find(&tables)
|
|
return
|
|
}
|
|
|
|
// GetCreateTableSQL 查询创建表语句
|
|
func (md *Mysqldump) GetCreateTableSQL(tableName string) (string, error) {
|
|
creates := make([]*CreateTable, 0)
|
|
err := md.conn.SQL(fmt.Sprintf("show create table %s", tableName)).Find(&creates)
|
|
log.Println(err)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
if len(creates) == 0 {
|
|
return "", errors.New("查询table 创建语句错误")
|
|
}
|
|
return creates[0].CreateTable, nil
|
|
}
|
|
|
|
// GetCreateDbSQL 获取创建数据库
|
|
func (md *Mysqldump) GetCreateDbSQL() (string, error) {
|
|
createSQLs := make([]*CreateDb, 0)
|
|
err := md.conn.SQL(fmt.Sprintf("SHOW CREATE DATABASE %s", md.cfg.DbCfg.DbName)).Find(&createSQLs)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
if len(createSQLs) == 0 {
|
|
return "", errors.New("查询创建数据库语句为空")
|
|
}
|
|
return createSQLs[0].CreateDatabase, nil
|
|
}
|
|
|
|
// ExportData 导出数据为
|
|
func (md *Mysqldump) ExportData(w io.Writer, tableName string) (err error) {
|
|
log.Println("开始导出数据:", tableName)
|
|
// 查询总数据行数
|
|
var count int64
|
|
count, err = md.conn.Table(tableName).Count()
|
|
if err != nil {
|
|
return
|
|
}
|
|
log.Println(count)
|
|
|
|
columns, xormColumns, err := md.conn.Dialect().GetColumns(tableName)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
var offset int64
|
|
for offset = 0; offset < count; offset += md.cfg.ExportDataStep {
|
|
colNames := md.conn.Dialect().Quote(strings.Join(columns, md.conn.Dialect().Quote(", ")))
|
|
sql := fmt.Sprintf("select %s from %s limit %d offset %d", colNames, tableName, md.cfg.ExportDataStep, offset)
|
|
list, err := md.conn.QueryInterface(sql)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for _, one := range list {
|
|
// 拼接插入语句头部
|
|
installSQL := fmt.Sprintf("\nINSERT INTO %s (%s) VALUES ",
|
|
md.conn.Dialect().Quote(tableName),
|
|
colNames)
|
|
values := make([]string, 0)
|
|
for _, column := range columns {
|
|
val, ok := one[column] // 读取本行值
|
|
if ok == false {
|
|
return errors.New("列名和值无法对应")
|
|
}
|
|
// 判断是否是时间类型
|
|
if xormColumn, ok := xormColumns[column]; ok == true {
|
|
aa[xormColumn.SQLType.Name] = xormColumn.SQLType.Name
|
|
if xormColumn.SQLType.IsTime() == true {
|
|
isTimeNull := false
|
|
if val == nil {
|
|
val = "null"
|
|
isTimeNull = true
|
|
} else {
|
|
valTime := val.(time.Time)
|
|
// valTime, err := time.ParseInLocation("2006-01-02T15:04:05Z", val.(string), time.UTC)
|
|
if err == nil {
|
|
val = valTime.Format("2006-01-02 15:04:05")
|
|
} else {
|
|
val = "null"
|
|
isTimeNull = true
|
|
}
|
|
}
|
|
if isTimeNull == true {
|
|
values = append(values, fmt.Sprintf("%v", val))
|
|
} else {
|
|
values = append(values, fmt.Sprintf("'%v'", val))
|
|
}
|
|
|
|
} else if xormColumn.SQLType.IsBlob() == true {
|
|
if val == nil {
|
|
val = "false"
|
|
} else {
|
|
if reflect.TypeOf(val).Kind() == reflect.Slice {
|
|
val = md.conn.Dialect().FormatBytes(val.([]byte))
|
|
} else if reflect.TypeOf(val).Kind() == reflect.String {
|
|
val = val.(string)
|
|
}
|
|
}
|
|
|
|
values = append(values, fmt.Sprintf("%v", val))
|
|
} else if xormColumn.SQLType.IsNumeric() == true {
|
|
if val == nil {
|
|
val = "null"
|
|
} else {
|
|
if valByte, ok := val.([]byte); ok == true {
|
|
// log.Println(column, "3-1")
|
|
val = string(valByte)
|
|
} else {
|
|
// log.Println(column, "3-2")
|
|
val = fmt.Sprint(val)
|
|
}
|
|
}
|
|
|
|
values = append(values, fmt.Sprintf("%v", val))
|
|
} else {
|
|
if val == nil {
|
|
val = ""
|
|
} else {
|
|
if valByte, ok := val.([]byte); ok == true {
|
|
// log.Println(column, "3-1")
|
|
val = string(valByte)
|
|
} else {
|
|
// log.Println(column, "3-2")
|
|
val = fmt.Sprint(val)
|
|
}
|
|
}
|
|
|
|
values = append(values, fmt.Sprintf("'%v'", val))
|
|
}
|
|
}
|
|
|
|
}
|
|
// 拼接插入语句值部分
|
|
installSQL = fmt.Sprintf("%s (%s);", installSQL, strings.Join(values, ","))
|
|
// 写入数据
|
|
_, err = io.WriteString(w, installSQL)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
}
|
|
return nil
|
|
}
|
|
|
|
var aa map[string]string
|
|
|
|
func init() {
|
|
aa = make(map[string]string, 0)
|
|
}
|
|
|