diff --git a/mayfly_go_web/src/views/ops/db/DbList.vue b/mayfly_go_web/src/views/ops/db/DbList.vue
index 3fa32a72..9591c3ac 100644
--- a/mayfly_go_web/src/views/ops/db/DbList.vue
+++ b/mayfly_go_web/src/views/ops/db/DbList.vue
@@ -80,8 +80,8 @@
详情
-
SQL执行记录
+ 导出
@@ -180,6 +180,26 @@
+
+
+
+ 结构
+ 数据
+ 结构+数据
+
+
+
+
+
+
+
+
+
+ 取消
+ 确定
+
+
+
{
state.showDumpInfo = false;
};
+const onDumpDbs = async (row: any) => {
+ const dbs = row.database.split(' ');
+ const data = []
+ for (let name of dbs) {
+ data.push({
+ key: name,
+ label: name,
+ })
+ }
+ state.exportDialog.value = []
+ state.exportDialog.data = data
+ state.exportDialog.dbId = row.id;
+ state.exportDialog.visible = true;
+};
+
+/**
+ * 数据库信息导出
+ */
+const dumpDbs = () => {
+ isTrue(state.exportDialog.value.length > 0, '请添加要导出的数据库');
+ const a = document.createElement('a');
+ a.setAttribute(
+ 'href',
+ `${config.baseApiUrl}/dbs/${state.exportDialog.dbId}/dump?db=${state.exportDialog.value.join(',')}&type=${state.exportDialog.type}&token=${getSession(
+ 'token'
+ )}`
+ );
+ a.click();
+ state.exportDialog.visible = false;
+};
+
const onShowRollbackSql = async (sqlExecLog: any) => {
const columns = await dbApi.columnMetadata.request({ id: sqlExecLog.dbId, db: sqlExecLog.db, tableName: sqlExecLog.table });
const primaryKey = getPrimaryKey(columns);
diff --git a/server/internal/db/api/db.go b/server/internal/db/api/db.go
index 4af65bf4..4cda8898 100644
--- a/server/internal/db/api/db.go
+++ b/server/internal/db/api/db.go
@@ -219,38 +219,71 @@ func (d *Db) ExecSqlFile(rc *req.Ctx) {
// 数据库dump
func (d *Db) DumpSql(rc *req.Ctx) {
g := rc.GinCtx
- db := getDbName(g)
+ dbId := getDbId(g)
+ dbNamesStr := g.Query("db")
dumpType := g.Query("type")
tablesStr := g.Query("tables")
- biz.NotEmpty(tablesStr, "请选择要导出的表")
- tables := strings.Split(tablesStr, ",")
// 是否需要导出表结构
needStruct := dumpType == "1" || dumpType == "3"
// 是否需要导出数据
needData := dumpType == "2" || dumpType == "3"
- dbInstance := d.getDbConnection(rc.GinCtx)
- biz.ErrIsNilAppendErr(d.TagApp.CanAccess(rc.LoginAccount.Id, dbInstance.Info.TagPath), "%s")
+ db := d.DbApp.GetById(dbId)
+ biz.ErrIsNilAppendErr(d.TagApp.CanAccess(rc.LoginAccount.Id, db.TagPath), "%s")
now := time.Now()
- filename := fmt.Sprintf("%s.%s.sql", db, now.Format("200601021504"))
+ filename := fmt.Sprintf("%s.%s.sql", db.Name, now.Format("20060102150405"))
g.Header("Content-Type", "application/octet-stream")
g.Header("Content-Disposition", "attachment; filename="+filename)
+ var dbNames, tables []string
+ if len(dbNamesStr) > 0 {
+ dbNames = strings.Split(dbNamesStr, ",")
+ }
+ if len(dbNames) == 1 && len(tablesStr) > 0 {
+ tables = strings.Split(tablesStr, ",")
+ }
writer := g.Writer
+ for _, dbName := range dbNames {
+ d.dumpDb(writer, db, dbName, tables, needStruct, needData)
+ }
+
+ rc.ReqParam = fmt.Sprintf("DB[id=%d, tag=%s, name=%s, databases=%s, tables=%s, dumpType=%s]", db.Id, db.TagPath, db.Name, dbNamesStr, tablesStr, dumpType)
+}
+
+func (d *Db) dumpDb(writer gin.ResponseWriter, db *entity.Db, dbName string, tables []string, needStruct bool, needData bool) {
writer.WriteString("-- ----------------------------")
writer.WriteString("\n-- 导出平台: mayfly-go")
- writer.WriteString(fmt.Sprintf("\n-- 导出时间: %s ", now.Format("2006-01-02 15:04:05")))
- writer.WriteString(fmt.Sprintf("\n-- 导出数据库: %s ", db))
+ writer.WriteString(fmt.Sprintf("\n-- 导出时间: %s ", time.Now().Format("2006-01-02 15:04:05")))
+ writer.WriteString(fmt.Sprintf("\n-- 导出数据库: %s ", dbName))
writer.WriteString("\n-- ----------------------------\n")
- dbmeta := d.getDbConnection(rc.GinCtx).GetMeta()
+ instance := d.InstanceApp.GetById(db.InstanceId)
+ dbInst := d.DbApp.GetDbConnection(db, instance, dbName)
+
+ switch dbInst.Info.Type {
+ case entity.DbTypeMysql:
+ writer.WriteString(fmt.Sprintf("use `%s`;\n", dbName))
+ case entity.DbTypePostgres:
+ writer.WriteString(fmt.Sprintf("\\connect `%s`;\n", dbName))
+ default:
+ biz.IsTrue(false, "数据库类型必须为 MySQL 或 PostgreSQL")
+ }
+ dbMeta := dbInst.GetMeta()
+ if len(tables) == 0 {
+ ti := dbMeta.GetTableInfos()
+ tables = make([]string, len(ti))
+ for i, table := range ti {
+ tables[i] = table.TableName
+ }
+ }
+
for _, table := range tables {
if needStruct {
writer.WriteString(fmt.Sprintf("\n-- ----------------------------\n-- 表结构: %s \n-- ----------------------------\n", table))
writer.WriteString(fmt.Sprintf("DROP TABLE IF EXISTS `%s`;\n", table))
- writer.WriteString(dbmeta.GetCreateTableDdl(table) + ";\n")
+ writer.WriteString(dbMeta.GetCreateTableDdl(table) + ";\n")
}
if !needData {
@@ -262,7 +295,7 @@ func (d *Db) DumpSql(rc *req.Ctx) {
pageNum := 1
for {
- columns, result, _ := dbmeta.GetTableRecord(table, pageNum, DEFAULT_ROW_SIZE)
+ columns, result, _ := dbMeta.GetTableRecord(table, pageNum, DEFAULT_ROW_SIZE)
resultLen := len(result)
if resultLen == 0 {
break
@@ -293,8 +326,6 @@ func (d *Db) DumpSql(rc *req.Ctx) {
writer.WriteString("COMMIT;\n")
}
-
- rc.ReqParam = fmt.Sprintf("%s, tables: %s, dumpType: %s", dbInstance.Info.GetLogDesc(), tablesStr, dumpType)
}
// @router /api/db/:dbId/t-metadata [get]