So implementieren Sie eine MySQL-Datenbanksicherung in Golang

So implementieren Sie eine MySQL-Datenbanksicherung in Golang

Hintergrund

Navicat ist das beste MySQL-Visualisierungstool. Beim Importieren und Exportieren von Ansichten verarbeitet es diese jedoch in alphabetischer Reihenfolge der Ansichtsnamen. Wenn Ansichten Abhängigkeiten aufweisen, werden während des Importvorgangs Fehler gemeldet. Ich habe zuvor eines in Python geschrieben, aber bei der Verwendung bin ich auf die Xfffd-Kodierung gestoßen und Pythons pymysql stürzte direkt ab. Ich habe festgestellt, dass Golang dieses Problem nicht hat, also habe ich es in Go neu geschrieben, um mich mit Golang vertraut zu machen.

Einige wichtige Punkte

  1. map & json, bei der Verarbeitung von Primärschlüssel- und Fremdschlüsselinformationen müssen Sie die JSON-Datenstruktur zum Speichern von Zwischenergebnissen verwenden. Da dies flexibel gehandhabt werden muss, kann es in Golang nur mit map[string]interface{} gehandhabt werden.
  2. interface{} entspricht einem Objekt in Java, das jeden Datentyp akzeptieren kann. Das ist praktisch, aber Sie müssen sich dessen bewusst sein, wenn Sie es verwenden, da das Programm sonst abstürzt, wenn der Datentyp nicht übereinstimmt.
  3. xfffd ist ein Platzhalter in utf8. Nachdem utf8mb4 außerhalb des Bereichs in der Datenbank gespeichert wurde, wird es als xfffd gespeichert. Beim Exportieren von Daten muss es herausgefiltert werden.
  4. goroutine, die Parallelitätsunterstützung von golang ist einzigartig. Unser Tool unterstützt die gleichzeitige Sicherung mehrerer Bibliotheken und es ist einfach, mit goroutine Parallelität zu erreichen.

Code-Analyse

Erklären Sie den Kerncode anhand des Funktionsmoduls

main.go, Parallelität, Befehlszeilenargumente

Verwenden Sie Befehlszeilenparameter, um einen Parameter zum Angeben des Sicherungsinhalts zu akzeptieren

Paket allgemein

Typ OpFlag-Struktur {
  Tables bool //Tabellenstruktur Datum bool //Tabellenstruktur und Daten Views bool //Ansicht Funcs bool //Funktionen und gespeicherte Prozeduren}

main.go, Programmeintrag, Verarbeitung von Kommandozeilenparametern

 wenn len(os.Args) > 1 {
    Flagge = allgemein.OpFlag{
      Tabellen: false,
      Datum: false,
      Ansichten: falsch,
      Funktionen: false,
    }
    switch os.Args[1] { //Akzeptiere einen Parameter case "table":
      flag.Tables = true //Setze den Bezeichner entsprechend dem Parameter case "data":
      flag.Tabellen = true
      flag.Datum = true
    Fall „Ansichten“:
      flag.Ansichten = true
    Fall "Funktionen":
      flag.Funcs = true
    Standard: //Falsche Parameter, Fehler melden und Protokoll beenden.Schwerwiegend("Ihr Argument muss in Tabelle, Daten, Ansichten oder Funktionen enthalten sein.")
    }
  }else{ //Keine Parameter, alle Flags werden standardmäßig exportiert = common.OpFlag{
      Tabellen: true,
      Datum: wahr,
      Ansichten: wahr,
      Funktionen: true,
    }
  }
  err := backUp.Export(flag) Sichern Sie die Datenbank entsprechend den Parametern

Exportieren.go

Sichern Sie den Hauptprozess, generieren Sie eine Goroutine gemäß configs.json, um die Datenbank zu sichern, und warten Sie, bis der Vorgang abgeschlossen ist.

var Konfigurationsschnittstelle{}
  fr, err := os.Open("./configs.json")
  wenn err != nil {
    Rückgabefehler
  }
  decoder := json.NewDecoder(fr) //Konfigurationsdatei analysieren err = decoder.Decode(&configs)
  confs := Konfigurationen.(map[string]Schnittstelle{})
  workDir := confs["workDir"].(Zeichenfolge)
  ch := make(chan string) //Kanalvariable für Schlüssel, Wert := Bereich confs {
    wenn strings.HasPrefix(Schlüssel, "db_") {
      dbConf := Wert.(map[string]interface{})
      dbConn := common.DbConnFields{ //Datenbankkonfiguration DbHost: dbConf["db_host"].(string),
        DbPort: int(dbConf["db_port"].(float64)),
        DbUser: dbConf["db_user"].(Zeichenfolge),
        DbPass: dbConf["db_pass"].(Zeichenfolge),
        DbName: dbConf["db_name"].(Zeichenfolge),
        DbCharset: dbConf["db_charset"].(Zeichenfolge),
      }
      if dbConf["file_alias"] != nil { //Generiere den Namen der SQL-Sicherungsdatei dbConn.FileAlias ​​​​= dbConf["file_alias"].(string)
      }
      go ExportOne(dbConn, workDir, ch, flag) //Coroutine erstellen}
  }
  for key := range confs { //Blockiere den Hauptprozess und warte bis alle Coroutinen ihre Arbeit beendet haben if strings.HasPrefix(key, "db_") {
      fmt.Print( <- ch )
    }
  }
  Rückgabe Null

Sie müssen die folgende Konfigurationsdatei schreiben, um die Datenbank zu beschreiben, die Sie sichern möchten:

{
  "Datenbankname1": {
    "db_host": "192.168.1.8",
    "db_port": 3306,
    "db_user": "root",
    "db_pass": "123456",
    "db_name": "name1",
    "db_charset": "utf8mb4",
    "file_alias": "Dateiname1"
  },
  "Datenbankname2": {
    "db_host": "lokaler Host",
    "db_port": 3306,
    "db_user": "root",
    "db_pass": "123456",
    "Datenbankname": "Name2",
    "db_charset": "utf8mb4"
  },
  "Datenbankdialekt": "mysql",
  "Arbeitsverzeichnis": "/home/zhoutk/gocodes/goTools/"
}

ExportOne.go

Sichern einer Datenbank

Dateiname := Felder.Dateialias
  setSqlHeader(fields, fileName) //Beschreibung der Exportdatei festlegen if flag.Tables { //Wenn die Tabelle auf true gesetzt ist, Tabellenstruktur exportieren err := exportTables(fileName, fields, flag) //Spezifische Algorithmen finden Sie im Quellcode if err != nil {
      ch <- fmt.Sprintln("Fehler: ", fields.DbName, "\t export tables throw, \t", err)
      zurückkehren
    }
  }
  if flag.Views { //Wenn die Ansicht auf „true“ gesetzt ist, exportiere die Ansicht err := exportViews(fileName, fields) //Den spezifischen Algorithmus findest du im Quellcode oder im Python-Algorithmus if err != nil {
      ch <- fmt.Sprintln("Fehler: ", fields.DbName, "\t export views throw, \t", err)
      zurückkehren
    }
  }
  if flag.Funcs { //Wenn die Funktion auf true gesetzt ist, werden Funktionen und gespeicherte Prozeduren exportiert err := exportFuncs(fileName, fields) //Spezifische Algorithmen finden Sie im Quellcode if err != nil {
      ch <- fmt.Sprintln("Fehler: ", fields.DbName, "\t export funcs throw, \t", err)
      zurückkehren
    }
  }
  //Export abgeschlossen, Eingabeinformationen zum Kanal ch <- fmt.Sprintln("Export ", fields.DbName, "\t Erfolg bei \t", time.Now().Format("2006-01-02 15:04:05"))

MysqlDao.go

Allgemeine Kapselung von Datenbankabfragen, dieses Tool verwendet nur ExecuteWithDbConn. Verwenden Sie map und interface{} flexibel, um die Ergebnisse in Schlüssel-Wert-Objekte umzuwandeln und zurückzugeben.

func ExecuteWithDbConn(sql string, Werte []Schnittstelle{}, Felder common.DbConnFields) (map[string]Schnittstelle{}, Fehler) {
  rs := make(map[string]schnittstelle{})
  dao, err := mysql.Open("mysql", Felder.DbUser + ":"+Felder.DbPass+"@tcp("+Felder.DbHost+":"+
    strconv.Itoa(Felder.DbPort)+")/"+Felder.DbName+"?charset="+Felder.DbCharset)
  verschieben dao.Close()
  wenn err != nil {
    rs["Code"] = 204
    returniere rs, err
  }
  stmt, err := dao.Vorbereiten(sql)
  wenn err != nil {
    rs["Code"] = 204
    returniere rs, err
  }
  Zeilen, Fehler := stmt.Query(Werte…)
  wenn err != nil {
    rs["Code"] = 204
    returniere rs, err
  }
  columns, err := rows.Columns() //Feldnamen abrufen vs := make([]mysql.RawBytes, len(columns))
  scannt := make([]interface{}, len(columns))
  für i := Bereich vs { //voreingestellter Wert Adresse scans[i] = &vs[i]
  }
  var Ergebnis []map[string]interface{}
  für Zeilen.Weiter() {
    _ = rows.Scan(scans...) //Geben Sie jeweils eine Spalte mit Werten ein := make(map[string]interface{})
    für i, col := Bereich vs {
      wenn col != nil {
        each[columns[i]] = FilterHolder(string(col)) //Filter/xfffd
      }anders{
        jede[Spalten[i]] = nil
      }
    }
    Ergebnis = Anhängen(Ergebnis, jedes)
  }
  rs["Code"] = 200
  //Daten, _ := json.Marshal(Ergebnis)
  rs["Zeilen"] = Ergebnis
  returniere rs, err
}

Projektgalerie

https://github.com/zhoutk/goTools

Anwendung

Git-Klon https://github.com/zhoutk/goTools
cd goTools
hol
Führen Sie main.go aus.
Erstellen Sie main.go
./main #alles aus der Datenbank exportieren
./Haupttabelle #Tabellen exportieren
./Hauptdaten #Tabellen und Daten exportieren
./Hauptansichten #Ansichten exportieren
./main funcs #Funktionen und gespeicherte Prozeduren exportieren

Zusammenfassen

Oben ist die vom Herausgeber vorgestellte Vorgehensweise zum Sichern einer MySQL-Datenbank mit Golang beschrieben. Ich hoffe, sie ist für alle hilfreich. Wenn Sie Fragen haben, hinterlassen Sie mir bitte eine Nachricht und der Herausgeber wird Ihnen rechtzeitig antworten. Ich möchte auch allen für ihre Unterstützung der Website 123WORDPRESS.COM danken!

Das könnte Sie auch interessieren:
  • Golang stellt über einen SSH-Proxy eine Verbindung zu MySQL her
  • Herstellen einer Verbindung zur MySQL-Datenbank in Golang
  • Führen Sie die Schritte von Golang aus, um eine MySql-Datenbank zu betreiben
  • So betreiben Sie MySQL in Golang
  • Implementierungscode zum Betreiben einer MySQL-Datenbank in Golang
  • Der Golang-Vorgang stellt eine Verbindung zur Datenbank her, um ein MySQL-Transaktionsbeispiel zu implementieren

<<:  Konventionelle JS-Verarbeitungsfunktionen für die Entwicklung von Vue Element-Frontend-Anwendungen

>>:  Linux löst das Problem, dass Deepin den Google Chrome-Browser nicht als Root-Benutzer starten kann

Artikel empfehlen

Implementierung der Master-Slave-Replikation im Docker Compose-Deployment

Inhaltsverzeichnis Konfigurationsanalyse Dienstle...

Typische Fälle von MySQL-Indexfehlern

Inhaltsverzeichnis Typische Fälle Anhang: Häufige...

Kapselungsmethode der Vue-Breadcrumbs-Komponente

Vue kapselt die Breadcrumb-Komponente zu Ihrer In...

So verwenden Sie Lottie-Animationen in React Native-Projekten

Lottie ist eine von Airbnb entwickelte Open-Sourc...

So implementieren Sie eine Remote-Verbindung für Redis unter Linux

Nachdem Sie Redis unter Linux installiert haben, ...

Beim Website-Design sollte auf die Farbhierarchie geachtet werden

Ich habe kürzlich gesagt, dass Design ein Gefühl d...

So richten Sie die passwortfreie SSH-Anmeldung beim Linux-Server ein

Bei jeder Anmeldung am Testserver ist grundsätzli...

Die HTML-Eingabedateisteuerung begrenzt den Typ der hochgeladenen Dateien

Fügen Sie der Webseite ein HTML-Steuerelement für...

Vue implementiert die Anmeldung mit grafischem Bestätigungscode

In diesem Artikelbeispiel wird der spezifische Co...

Detaillierte Erklärung zur Verwendung mehrerer Timer in CocosCreator

1. setTimeOut Drucken Sie abc nach 3 Sekunden. Nu...