GolangでMySQLデータベースのバックアップを実装する方法

GolangでMySQLデータベースのバックアップを実装する方法

背景

Navicat は、最高の MySQL 視覚化ツールです。ただし、ビューのインポートとエクスポートに関しては、ビュー名のアルファベット順に処理されます。ビューに依存関係がある場合は、インポート プロセス中にエラーが報告されます。以前 Python で書いたことがありますが、それを使用すると xfffd エンコーディングが発生し、Python の pymysql が直接クラッシュしてしまいました。 golang にはこの問題がないことがわかったので、golang に慣れるために go で書き直しました。

いくつかの重要なポイント

  1. map & jsonでは、主キーと外部キーの情報を処理する際に、中間結果を格納するためにjsonデータ構造を使用する必要があります。柔軟に対応する必要があるため、golangではmap[string]interface{}でしか扱うことができません。
  2. interface{} は Java のオブジェクトに相当し、任意のデータ型を受け入れることができます。これは便利ですが、使用時には注意が必要です。そうしないと、データ型が一致しない場合にプログラムがクラッシュします。
  3. xfffd は utf8 のプレースホルダーです。範囲外の utf8mb4 がデータベースに保存されると、xfffd として保存されます。データをエクスポートするときには、これを除外する必要があります。
  4. goroutine は、golang の並行処理サポートがユニークです。当社のツールは、複数のライブラリの同時バックアップをサポートしており、goroutine を使用して簡単に並列処理を実現できます。

コード分​​析

機能モジュールごとにコアコードを説明する

main.go、並行性、コマンドライン引数

コマンドラインパラメータを使用して、バックアップコンテンツを指定するパラメータを受け入れます。

パッケージ共通

OpFlag構造体型{
  Tables bool //テーブル構造 Datum bool //テーブル構造とデータ Views bool //ビュー Funcs bool //関数とストアドプロシージャ}

main.go、プログラムエントリ、コマンドラインパラメータの処理

 len(os.Args) > 1 の場合 {
    フラグ = common.OpFlag{
      表: 偽、
      データ: 偽、
      閲覧数: false、
      関数: false、
    }
    switch os.Args[1] { //パラメータを受け入れる case "table":
      flag.Tables = true //パラメータケース「data」に応じて識別子を設定します。
      flag.Tables = true
      flag.Datum = true
    ケース「ビュー」:
      flag.Views = true
    ケース "関数":
      flag.Funcs = true
    デフォルト: // パラメータが正しくありません。エラーを報告してログを終了します。致命的("引数はテーブル、データ、ビュー、または関数内になければなりません。")
    }
  }else{ //パラメータなし、すべてのフラグはデフォルトでエクスポートされます = common.OpFlag{
      表: 真、
      データ: true、
      閲覧数: true、
      関数: true、
    }
  }
  err := backUp.Export(flag) パラメータに従ってデータベースをバックアップします

エクスポート.go

メインプロセスをバックアップし、configs.json に従って goroutine を生成してデータベースをバックアップし、完了を待ちます。

var configs インターフェース{}
  fr, err := os.Open("./configs.json")
  err != nil の場合 {
    エラーを返す
  }
  デコーダー:= json.NewDecoder(fr) // 設定ファイルを解析します err = デコーダー.Decode(&configs)
  confs := configs.(map[文字列]インターフェース{})
  workDir := confs["workDir"].(文字列)
  ch := make(chan string) //キーのチャネル変数、値 := range confs {
    strings.HasPrefix(キー、"db_") の場合 {
      dbConf := 値.(map[文字列]インターフェース{})
      dbConn := common.DbConnFields{ //データベース構成 DbHost: dbConf["db_host"].(文字列),
        DbPort: int(dbConf["db_port"].(float64))、
        DbUser: dbConf["db_user"].(文字列)、
        DbPass: dbConf["db_pass"].(文字列)、
        DbName: dbConf["db_name"].(文字列)、
        DbCharset: dbConf["db_charset"].(文字列)、
      }
      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) 関数は、
    }
  }
  nilを返す

バックアップするデータベースを記述するには、次の構成ファイルを作成する必要があります。

{
  "db_name1": {
    "db_host": "192.168.1.8",
    「db_port」: 3306,
    "db_user": "ルート",
    "db_pass": "123456",
    "db_name": "name1",
    "db_charset": "utf8mb4",
    "file_alias": "ファイル名1"
  },
  "db_name2": {
    "db_host": "ローカルホスト",
    「db_port」: 3306,
    "db_user": "ルート",
    "db_pass": "123456",
    "db_name": "name2",
    "db_charset": "utf8mb4"
  },
  "データベース方言": "mysql",
  "作業ディレクトリ": "/home/zhoutk/gocodes/goTools/"
}

エクスポートワン

データベースのバックアップ

ファイル名:= フィールド.FileAlias
  setSqlHeader(fields, fileName) //エクスポートファイルの説明を設定します if flag.Tables { //テーブルがtrueに設定されている場合、テーブル構造をエクスポートします err := exportTables(fileName, fields, flag) //特定のアルゴリズムについては、ソースコードを参照してください if err != nil {
      ch <- fmt.Sprintln("エラー: ", fields.DbName, "\t エクスポート テーブルがスローされました, \t", err)
      戻る
    }
  }
  if flag.Views { //ビューがtrueに設定されている場合、ビューをエクスポートします err := exportViews(fileName, fields) //具体的なアルゴリズムについては、ソースコードまたはPythonアルゴリズムを参照してください if err != nil {
      ch <- fmt.Sprintln("エラー: ", fields.DbName, "\t エクスポート ビューがスローされました, \t", err)
      戻る
    }
  }
  if flag.Funcs { //関数がtrueに設定されている場合、関数とストアドプロシージャをエクスポートします err := exportFuncs(fileName, fields) //具体的なアルゴリズムについては、ソースコードを参照してください if err != nil {
      ch <- fmt.Sprintln("エラー: ", fields.DbName, "\t export funcs throw, \t", err)
      戻る
    }
  }
  //エクスポートが完了しました。チャネルに情報を入力します。 ch <- fmt.Sprintln("エクスポート ", fields.DbName, "\t 成功 \t", time.Now().Format("2006-01-02 15:04:05"))

翻訳元

データベース クエリの一般的なカプセル化。このツールは ExecuteWithDbConn のみを使用します。 map と interface{} を柔軟に使用して、結果をキー値オブジェクトに変換して返します。

func ExecuteWithDbConn(sql 文字列、値 [] インターフェース {}、フィールド common.DbConnFields) (map [文字列] インターフェース {}、エラー) {
  rs := make(map[文字列]インターフェース{})
  dao、err := mysql.Open("mysql", fields.DbUser + ":"+fields.DbPass+"@tcp("+fields.DbHost+":"+
    strconv.Itoa(fields.DbPort)+")/"+fields.DbName+"?charset="+fields.DbCharset)
  dao.Close() を延期する
  err != nil の場合 {
    rs["コード"] = 204
    rsを返す、エラー
  }
  stmt、err := dao.Prepare(sql)
  err != nil の場合 {
    rs["コード"] = 204
    rsを返す、エラー
  }
  行、エラー:= stmt.Query(値...)
  err != nil の場合 {
    rs["コード"] = 204
    rsを返す、エラー
  }
  columns, err := rows.Columns() //フィールド名を取得します vs := make([]mysql.RawBytes, len(columns))
  スキャン:= make([]interface{}, len(列))
  for i := range vs { // プリセット値アドレス scans[i] = &vs[i]
  }
  var result []map[文字列]インターフェース{}
  行のNext() {
    _ = rows.Scan(scans...) //値の列を入力します each := make(map[string]interface{})
    i, col := 範囲 vs {
      列がnilの場合{
        each[columns[i]] = FilterHolder(string(col)) //Filter/xfffd
      }それ以外{
        各[列[i]] = nil
      }
    }
    結果 = append(結果、それぞれ)
  }
  rs["コード"] = 200
  //データ、_ := json.Marshal(結果)
  rs["行"] = 結果
  rsを返す、エラー
}

プロジェクトギャラリー

https://github.com/zhoutk/goTools

使い方

git クローン https://github.com/zhoutk/goTools
cd goツール
取りに行く
main.go を実行します
ビルド main.go
./main #データベースのすべてをエクスポート
./main テーブル #テーブルをエクスポート
./main data #テーブルとデータをエクスポート
./メインビュー #エクスポートビュー
./main funcs #export 関数とストアド プロシージャ

要約する

上記は、編集者が紹介したgolangを使用してmysqlデータベースをバックアップする操作方法です。皆様のお役に立てれば幸いです。ご質問がある場合は、メッセージを残してください。編集者がすぐに返信します。また、123WORDPRESS.COM ウェブサイトをサポートしてくださっている皆様にも感謝申し上げます。

以下もご興味があるかもしれません:
  • GolangはSSHプロキシ経由でMySQLに接続する
  • Golang で MySQL データベースに接続する
  • GolangでMySqlデータベースを操作するための完全な手順
  • GolangでMySQLを操作する方法
  • GolangでMySQLデータベースを操作するための実装コード
  • Golang 操作はデータベースに接続して、mysql トランザクションの例を実装します。

<<:  Vue Element フロントエンドアプリケーション開発のための従来の JS 処理機能

>>:  Linux は、Deepin がルートユーザーとして Google Chrome ブラウザを起動できない問題を解決します

推薦する

docker を使用して crownblog プロジェクトを Alibaba Cloud にデプロイする方法

フロントエンドプロジェクトのパッケージ化.env.productionを見つけて、自分のIPまたはド...

MySQL で浮動小数点データを文字データに変換するときに起こりうる問題の詳細な説明

序文この記事は主に、MySQL で浮動小数点型を文字型に変換するときに発生する問題を紹介します。これ...

SQL文のANDとORの実行順序で発生する問題

質問昨日、データベースSQLを書いているときに問題が発生しました。問題の根本は、SQL ステートメン...

Docker で Maven プロジェクトをより速くビルドする

目次I. 概要2. 従来の多段階イメージ構築3. Buildkitを使用してイメージをビルドする4....

MySQL の undo、redo、binlog の違いを簡単に分析します

目次序文【ログ取り消し】 【REDOログ】 【バイナリログ】要約する序文MySQL には、REDO ...

VMWare仮想マシンのcentosの時間が現地時間と矛盾する問題を解決する

VM Ware 仮想マシン CentOS の時刻は、次の図に示すように、現地時間と一致しません。おそ...

MySQL 5.7.20 共通ダウンロード、インストール、設定方法と簡単な操作スキル(解凍版無料インストール)

早朝に MySQL 5.7.19 のインストールを終えたばかりですが、午前中に MySQL が最新バ...

vue3.2 で追加された defineCustomElement の基本原理の詳細な説明

目次Webコンポーネントカスタム要素概要HTMLTemplateElement コンテンツ テンプレ...

Vue要素ツリーコントロールに点線を追加する詳細な説明

目次1. 成果を達成する2. 実装コード3. その他の実装要約する1. 成果を達成する 2. 実装コ...

よくある MySQL テーブル設計エラーの概要

目次間違い1: データの列が多すぎる誤解2: 共同クエリが多すぎる誤解3: ENUMの代わりにSET...

RHEL8 で静的 IP アドレスを設定するさまざまな方法の簡単な分析

Linux サーバーで作業している場合、ネットワーク カード/イーサネット カードに静的 IP アド...

MySQL innodb B+ツリーの高さを取得する方法

序文MySQL の InnoDB エンジンがインデックスの保存に B+tree を使用する理由は、デ...

HTML&CSS&JS 互換性ツリー (IE、Firefox、Chrome)

Web デザインにおけるツリーとは何ですか?簡単に言うと、リンクをクリックするとサブディレクトリが展...

VUE 応答性原理の詳細な説明

目次1. 応答原理の基盤2. コアオブジェクト: Dep と Watcher 3. 依存関係を収集し...