Implementieren Sie eine einfache CRUD mit Go + MySQL + Docker

Einführung

Neulich dachte ich: "Ich habe nicht vor, es für geschäftliche Zwecke zu verwenden, aber ich sollte etwas über Go wissen ...", also habe ich versucht, eine einfache CRUD mit Go zu implementieren, damit ich die Methode als Memorandum zusammenfassen kann. Ich werde.

Grundsätzlich ist es ein wenig angeordnet, indem der Inhalt der folgenden Websites kombiniert wird. Bitte beziehen Sie sich auf diese Seiten, da sie beim Lernen von Go sehr hilfreich waren. Erstellen einer Go-Entwicklungsumgebung mit Docker Erstellen Sie mit Go / Gin eine supereinfache Web-App Einführung in Go Language-MySQL Connection- Erstellen Sie einen DB-Container für Docker-Compose MySQL8.0 Wie man wartet, bis MySQL mit Docker-Compose beginnt (2 Typen eingeführt)

Starten Sie Go with Docker

Zunächst werden wir Go with Docker starten. Direkt unter dem Arbeitsverzeichnis

DockerFile


FROM golang:latest

RUN mkdir /app
WORKDIR /app

docker-compose.yml


version: '3'
services:
  go:
    build:
      context: .
      dockerfile: DockerFile
    command: /bin/sh -c "go run main.go"
    stdin_open: true
    tty: true
    volumes:
      - .:/app

main.go


package main

import "fmt"

func main() {
  fmt.Println("Hello, World!")
}

Wenn Sie damit "Docker-Compose" machen, sehen Sie Hallo, Welt! Auf der Konsole. Wenn dies herauskommt, ist der Start von Go erfolgreich.

Ich werde jede Datei kurz erklären. ・ DockerFile Erstellen Sie einen Go-Container (virtuelle Umgebung). Wenn Sie hier "WORKDIR / app" angeben, werden alle nachfolgenden Vorgänge unter "/ app" ausgeführt.

・ Docker-compose.yml Schreiben Sie die Einstellungen beim Starten des mit DockerFile erstellten Containers. Dadurch wird ein Container in DockerFile gestartet und der Befehl "go run main.go" ausgeführt, um main.go zu starten.

・ Main.go Ich werde die Verarbeitung in Bezug auf Go hier schreiben. Dieses Mal müssen Sie nur Hallo, Welt! Ausgeben.

Erstellen Sie eine Webseite in Go

Nachdem Go gestartet wurde, erstellen wir mit Go eine Webseite. Dieses Mal werde ich ein Framework namens Gin verwenden.

DockerFile


FROM golang:latest

RUN mkdir /app
WORKDIR /app

RUN go get github.com/gin-gonic/gin

docker-compose.yml


version: '3'
services:
  go:
    build:
      context: .
      dockerfile: DockerFile
    command: /bin/sh -c "go run main.go"
    stdin_open: true
    tty: true
    volumes:
      - .:/app
    ports:
      - 8080:8080

main.go


package main

import (
  "github.com/gin-gonic/gin"
)

func main() {
  router := gin.Default()
  router.LoadHTMLGlob("templates/*.html")

  router.GET("/", func(ctx *gin.Context){
    ctx.HTML(200, "index.html", gin.H{})
  })

  router.Run()
}

templates/index.html


<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>Sample App</title>
</head>
<body>
  <h1>Hello World!!!</h1>
</body>
</html>

mit diesem

docker-compose build
docker-compose up -d

Nach einer Weile warten Wenn Sie auf [http: // localhost: 8080](http: // localhost: 8080) zugreifen, wird Hello World!

Ich werde erklären, was ich diesmal getan habe. Dieses Mal habe ich ein Framework namens Gin hinzugefügt. Gin wird mit dem Befehl go get github.com / gin-gonic / gin nach dem Erstellen eines Containers mit DockerFile installiert und von main.go aufgerufen. Und der Inhalt von Vorlagen wird in main.go gelesen,

router.GET("/", func(ctx *gin.Context){
  ctx.HTML(200, "index.html", gin.H{})
})

Wird mit templates / index.html für root ("/") verknüpft. Wenn Sie das erste Argument ("/") von router.GET in "/ test" usw. ändern, ist es übrigens nicht [http: // localhost: 8080](http: // localhost: 8080), sondern [http: // localhost Index.html wird angezeigt unter: 8080 / test](http: // localhost: 8080 / test).

Fügen Sie abschließend einen Port zu docker-compose.yml hinzu, um den Zugriff auf localhost: 8080 zu ermöglichen.

Starten Sie MySQL mit Docker

Zu diesem Zeitpunkt können Sie mit Go Webseiten erstellen. In der Realität wird jedoch beim Erstellen eines Webdienstes eine Verbindung mit der Datenbank unvermeidbar. Als nächstes werden wir MySQL mit Docker starten.

Zuerst in docker-compose.yml -Beschreibung des Datenbankcontainers ・ Volumenbeschreibung Bitte hinzufügen.

docker-compose.yml


db:
  image: mysql:8.0
  environment:
    MYSQL_ROOT_PASSWORD: root
    MYSQL_DATABASE: go_database
    MYSQL_USER: go_test
    MYSQL_PASSWORD: password
    TZ: 'Asia/Tokyo'
  command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
  volumes:
    - db-data:/var/lib/mysql
    - ./db/my.cnf:/etc/mysql/conf.d/my.cnf
  ports:
    - 3306:3306

volumes:
  db-data:
    driver: local

Erstellen Sie außerdem ein Datenbankverzeichnis und eine my.cnf-Datei darin.

my.cnf


[mysqld]
character-set-server = utf8mb4
collation-server = utf8mb4_bin

default-time-zone = SYSTEM
log_timestamps = SYSTEM

default-authentication-plugin = mysql_native_password

[mysql]
default-character-set = utf8mb4

[client]
default-character-set = utf8mb4

(Dieser Bereich entspricht der Referenzseite. Nur der Teil, der sich auf das Protokoll bezieht, hat aus irgendeinem Grund nicht funktioniert, daher habe ich ihn entfernt.)

Wenn Sie bisher "docker-compose up -d" ausführen, sollte auch der MySQL-Container gestartet werden. Da es nur eine Beschreibung der Einstellungen gibt, wird die Erklärung hier weggelassen.

Verbinden Sie Go und MySQL

Nachdem MySQL gestartet wurde, werde ich es sofort mit Go verbinden. Dieses Mal werden wir den SQL-Treiber und ein Framework namens GORM für die Verbindung verwenden.

DockerFile


FROM golang:latest

RUN mkdir /app
WORKDIR /app

RUN go get github.com/gin-gonic/gin
RUN go get github.com/go-sql-driver/mysql
RUN go get github.com/jinzhu/gorm

docker-compose.yml


version: '3'
services:
  go:
    build:
      context: .
      dockerfile: DockerFile
    command: /bin/sh -c "go run main.go"
    stdin_open: true
    tty: true
    volumes:
      - .:/app
    ports:
      - 8080:8080
    depends_on:
      - "db"

  db:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: go_database
      MYSQL_USER: go_test
      MYSQL_PASSWORD: password
      TZ: 'Asia/Tokyo'
    command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
    volumes:
      - db-data:/var/lib/mysql
      - ./db/my.cnf:/etc/mysql/conf.d/my.cnf
    ports:
      - 3306:3306

volumes:
  db-data:
    driver: local

main.go


package main

import (
  "fmt"
  "time"

  "github.com/gin-gonic/gin"
  "github.com/jinzhu/gorm"
  _ "github.com/go-sql-driver/mysql"
)

func main() {
  db := sqlConnect()
  defer db.Close()
	
  router := gin.Default()
  router.LoadHTMLGlob("templates/*.html")

  router.GET("/", func(ctx *gin.Context){
    ctx.HTML(200, "index.html", gin.H{})
  })

  router.Run()
}

func sqlConnect() (database *gorm.DB) {
  DBMS := "mysql"
  USER := "go_test"
  PASS := "password"
  PROTOCOL := "tcp(db:3306)"
  DBNAME := "go_database"

  CONNECT := USER + ":" + PASS + "@" + PROTOCOL + "/" + DBNAME + "?charset=utf8&parseTime=true&loc=Asia%2FTokyo"
  
  count := 0
  db, err := gorm.Open(DBMS, CONNECT)
  if err != nil {
    for {
      if err == nil {
        fmt.Println("")
        break
      }
      fmt.Print(".")
      time.Sleep(time.Second)
      count++
      if count > 180 {
        fmt.Println("")
        fmt.Println("DB-Verbindungsfehler")
        panic(err)
      }
      db, err = gorm.Open(DBMS, CONNECT)
    }
  }
  fmt.Println("DB-Verbindung erfolgreich")

  return db
}

Jetzt "Docker komponieren" und wenn die Konsole "DB-Verbindung erfolgreich" anzeigt, ist es erfolgreich.

Da sqlConnect der Hauptinhalt ist, werde ich es erklären.

func sqlConnect() (database *gorm.DB) {
  DBMS := "mysql"
  USER := "go_test"
  PASS := "password"
  PROTOCOL := "tcp(db:3306)"
  DBNAME := "go_database"

  CONNECT := USER + ":" + PASS + "@" + PROTOCOL + "/" + DBNAME + "?charset=utf8&parseTime=true&loc=Asia%2FTokyo"
  
  count := 0
  db, err := gorm.Open(DBMS, CONNECT)
  if err != nil {
    for {
      if err == nil {
        fmt.Println("")
        break
      }
      fmt.Print(".")
      time.Sleep(time.Second)
      count++
      if count > 180 {
        fmt.Println("")
        fmt.Println("DB-Verbindungsfehler")
        panic(err)
      }
      db, err = gorm.Open(DBMS, CONNECT)
    }
  }
  fmt.Println("DB-Verbindung erfolgreich")

  return db
}

In der ersten Hälfte werden die Informationen für die Verbindung zur Datenbank definiert. Bitte geben Sie den Inhalt in docker-compose.yml ein. Stellen Sie dann mit db, err: = gorm.Open (DBMS, CONNECT) eine Verbindung zur DB her. Abhängig von der Startzeit von MySQL ist MySQL möglicherweise zum Zeitpunkt der Ausführung dieses Befehls nicht bereit. Daher ergreift dieser Code zwei Maßnahmen.

Die erste ist die Abhängigkeitseinstellung in docker-compose.yml. Wenn Sie hier abhängige_on festlegen, wird der Go-Container nach dem Start des DB-Containers gestartet.

Die zweite ist die Wiederholungsverarbeitung. Selbst nachdem der Datenbankcontainer gestartet wurde, dauert es einige Zeit, bis MySQL gestartet ist. Wenn also keine Verbindung zur Datenbank hergestellt wird, warte ich 1 Sekunde und versuche es dann erneut. Wenn dies der Fall ist, wird es weiterhin versucht, wenn ein echter Fehler vorliegt. Versuchen Sie daher, den Fehler eine angemessene Anzahl von Malen zurückzugeben. In diesem Code tritt ein Fehler auf, wenn 3 Minuten lang keine Verbindung hergestellt wird.

Implementieren Sie CRUD

Schließlich ist es mit MySQL verbunden. Lassen Sie uns also endlich die CRUD-Verarbeitung implementieren und den tatsächlichen Ablauf sehen. Nur main.go und index.html werden geändert.

main.go


package main

import (
  "fmt"
  "strconv"
  "time"

  "github.com/gin-gonic/gin"
  "github.com/jinzhu/gorm"
  _ "github.com/go-sql-driver/mysql"
)

type User struct {
  gorm.Model
  Name string
  Email string
}

func main() {
  db := sqlConnect()
  db.AutoMigrate(&User{})
  defer db.Close()

  router := gin.Default()
  router.LoadHTMLGlob("templates/*.html")

  router.GET("/", func(ctx *gin.Context){
    db := sqlConnect()
    var users []User
    db.Order("created_at asc").Find(&users)
    defer db.Close()

    ctx.HTML(200, "index.html", gin.H{
      "users": users,
    })
  })

  router.POST("/new", func(ctx *gin.Context) {
    db := sqlConnect()
    name := ctx.PostForm("name")
    email := ctx.PostForm("email")
    fmt.Println("create user " + name + " with email " + email)
    db.Create(&User{Name: name, Email: email})
    defer db.Close()

    ctx.Redirect(302, "/")
  })

  router.POST("/delete/:id", func(ctx *gin.Context) {
    db := sqlConnect()
    n := ctx.Param("id")
    id, err := strconv.Atoi(n)
    if err != nil {
      panic("id is not a number")
    }
    var user User
    db.First(&user, id)
    db.Delete(&user)
    defer db.Close()

    ctx.Redirect(302, "/")
  })

  router.Run()
}

func sqlConnect() (database *gorm.DB) {
  DBMS := "mysql"
  USER := "go_test"
  PASS := "password"
  PROTOCOL := "tcp(db:3306)"
  DBNAME := "go_database"

  CONNECT := USER + ":" + PASS + "@" + PROTOCOL + "/" + DBNAME + "?charset=utf8&parseTime=true&loc=Asia%2FTokyo"
  
  count := 0
  db, err := gorm.Open(DBMS, CONNECT)
  if err != nil {
    for {
      if err == nil {
        fmt.Println("")
        break
      }
      fmt.Print(".")
      time.Sleep(time.Second)
      count++
      if count > 180 {
        fmt.Println("")
        panic(err)
      }
      db, err = gorm.Open(DBMS, CONNECT)
    }
  }

  return db
}

templates/index.html


<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>Sample App</title>
</head>
<body>
  <h2>Benutzer hinzufügen</h2>
  <form method="post" action="/new">
    <p>Name<input type="text" name="name" size="30" placeholder="Bitte eingeben" ></p>
    <p>Mail Adresse<input type="text" name="email" size="30" placeholder="Bitte eingeben" ></p>
    <p><input type="submit" value="Send"></p>
  </form>
  
  <h2>Benutzerliste</h2>
  <table>
    <tr>
      <td>Name</td>
      <td>Mail Adresse</td>
    </tr>
    {{ range .users }}
      <tr>
        <td>{{ .Name }}</td>
        <td>{{ .Email }}</td>
        <td>
          <form method="post" action="/delete/{{.ID}}">
            <button type="submit">Löschen</button>
          </form>
        </td>
      </tr>
    {{ end }}
  </ul>
  </body>
</html>

Führen Sie nun "docker-compose up -d" aus. Wenn Sie auf [http: // localhost: 8080](http: // localhost: 8080) zugreifen, wird das Benutzerregistrierungsformular angezeigt. Wenn Sie den Benutzer registrieren, wird der unten angegebene Benutzer registriert Die Informationen werden angezeigt. Auch wenn Sie den Container löschen und erneut anheben, wird der registrierte Benutzer nicht gelöscht und bleibt in der Benutzerliste angezeigt.

Dann werde ich den zusätzlichen Teil erklären. Zuerst erstelle ich eine Struktur namens User in main.go. In gorm.Model werden die für das Modell erforderlichen Inhalte wie ID in Benutzer eingegeben und benutzerspezifischer Name und E-Mail-Adresse hinzugefügt. Diese Struktur spiegelt sich in der DB durch db.AutoMigrate wider.

Als nächstes werden wir die CRUD-Verarbeitung in jedem Pfad implementieren.

Holen Sie sich die Benutzerliste in den Stammpfad. Verwenden Sie db.Find (& users), um die Liste der Benutzer in der Datenbank als Benutzerstruktur abzurufen. Wenn Sie eine Bestellung dazwischen aufgeben, wird der alte Benutzer zum Zeitpunkt des Erwerbs angezeigt. Wir übergeben den zuletzt abgerufenen Benutzer an index.html.

Der Pfad / new erstellt einen Benutzer basierend auf dem Inhalt des Formulars. Ich erhalte den vom Formular übermittelten Inhalt mit ctx.PostForm und behalte den Inhalt mit db.Create bei. Weiterleiten an root, wenn Sie fertig sind.

Der Pfad / delete gibt die ID an, mit der der Benutzer gelöscht werden soll. Hier wird die Benutzer-ID in der URL angegeben, sie wird jedoch auch von ctx abgerufen. Holen Sie sich dann den Benutzer mit db.First aus dem Inhalt und löschen Sie den Benutzer mit db.Delete. Beachten Sie, dass die ID als Zeichenfolge übergeben wird, sodass strconv.Atoi sie in einen int-Typ konvertiert.

In index.html werden Formular und Tabelle mit der allgemeinen HTML-Schreibmethode erstellt. Hier empfangen wir die von main.go übergebenen Benutzer in der Form "{{range .users}}".

abschließend

Dieses Mal habe ich versucht, eine einfache CRUD mit Go + MySQL + Docker als Einführung in die Webdienstentwicklung mit Go zu implementieren. Es ist nur eine Übung, daher denke ich nicht an Validierung oder Feinkontrolle. Der Inhalt, den ich diesmal gemacht habe, ist rudimentär, aber ich denke, dass Sie tatsächlich einen Webdienst erstellen können, indem Sie diesen Inhalt erweitern und komplizieren. Wenn jemand etwas mit Go machen möchte, beziehen Sie sich bitte darauf!

Recommended Posts

Implementieren Sie eine einfache CRUD mit Go + MySQL + Docker
Implementieren Sie CRUD mit Spring Boot + Thymeleaf + MySQL
[Umgebungskonstruktion mit Docker] Rails 6 & MySQL 8
Aktualisieren Sie MySQL mit Docker von 5.7 auf 8.0
Implementieren Sie einen einfachen Web-REST-API-Server mit Spring Boot + MySQL
Mit Docker auf Heroku bereitstellen (Rails 6, MySQL)
Bearbeiten Sie MySQL mit Befehlen in der Docker-Umgebung
[Docker] [Nginx] Erstellen Sie mit Nginx eine einfache ALB
Erstellen einer Umgebung für Laravel + MySQL + phpMyadmin mit Docker
Bildposting mit [Docker + WordPress + MySQL] zulassen
Erstellen Sie mit Java + MySQL ein einfaches Bulletin Board
Üben Sie das Erstellen einer einfachen Chat-App mit Docker + Sinatra
Implementieren Sie eine einfache Rest-API mit Spring Security mit Spring Boot 2.0
Build Rails (API) x MySQL x Nuxt.js Umgebung mit Docker
Explodiere Docker mit WSL2
Verwenden Sie Puphpeteer mit Docker
Bedienen Sie Emby mit Docker
Führen Sie Payara mit Docker aus
[Rails] Entwicklung mit MySQL
Ich habe versucht, einen API-Server mit Go (Echo) x MySQL x Docker x Clean Architecture zu erstellen
Einweg-PHP mit Docker
Erstellen Sie eine einfache CRUD mit SpringBoot + JPA + Thymeleaf ~ ~ Validierung hinzufügen ~
So erstellen Sie mit Docker ~ Express ~ eine [TypeScript + Vue + Express + MySQL] -Umgebung
Erstellen Sie mit SpringBoot + JPA + Thymeleaf ein einfaches CRUD ~ ~ Hallo Welt ~
Erstellen Sie eine Entwicklungsumgebung für Rails-Anwendungen mit Docker [Docker, Rails, Puma, Nginx, MySQL]
Erstellen Sie eine einfache CRUD mit SpringBoot + JPA + Thymeleaf ⑤ ~ Common template ~
docker-compose.yml, wenn Sie MySQL auf Docker laufen lassen möchten
Ein einfaches CRUD-Beispiel mit Java Servlet / JSP und MySQL
Implementieren Sie eine einfache Rest-API mit Spring Security & JWT mit Spring Boot 2.0
Maßnahmen für Berechtigungen beim Erstellen von MySQL mit Docker auf WSL2