使用Go语言(GoLang)创建一个使用MySQL的API

前言

在构建API时,考虑到需要支持大规模的并发连接,因此决定用Golang重新创建之前用Python的Django创建的API。

因为有很多无法按照计划进行的情况和太多的困难,所以将其记录下来。

用Python验证是否能超越Go在性能上。

设置Go的环境

下载Go

// 確認
% go version
go version go1.16.2 darwin/amd64

// 環境情報
% go env
GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/Users/akidon/Library/Caches/go-build"
GOENV="/Users/akidon/Library/Application Support/go/env"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOINSECURE=""
GOMODCACHE="/Users/akidon/go/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="darwin"
GOPATH="/Users/akidon/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/usr/local/go"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/darwin_amd64"
GOVCS=""
GOVERSION="go1.16.2"
GCCGO="gccgo"
AR="ar"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOMOD="/Users/akidon/program/go/goAPI/go.mod"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -arch x86_64 -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/qg/6f_bf3fx4qs2gxwzhbc_pks00000gn/T/go-build311814080=/tmp/go-build -gno-record-gcc-switches -fno-common"

// PATH追加
% open ~/.zshrc

请添加以下内容

#Goのパス
export GOROOT=/usr/local/go
export GOPATH=$HOME/go
export PATH=$GOROOT/bin:$PATH
export PATH=$GOPATH/bin:$PATH

确认动作

在适当的文件夹中创建名为hello.go的文件,并使用Visual Studio Code进行如下所示的编辑。

package main

import "fmt"

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

在终端中切换到先前的文件夹,并执行 “go run hello.go” 命令。如果显示 “Hello!”,则表示成功。

% go run hello.go
Hello!

Go的套件

回声…创建 RestfulAPI(还有 Gin 和 Gorilla 等其他选项)
Gorm…用于操作 MySQL

如果遇到以下错误:
找不到包 “github.com/hoge”
只需执行 go get github.com/hoge 即可。

% go mod init go-tools

% go get github.com/labstack/echo
% go get github.com/jinzhu/gorm
% go get github.com/joho/godotenv

请下载MySQL。

从Mac的初始设置备忘录中下载MySQL。

% mysql.server start 
// mysql.server stop でサーバー停止

# MySQLに入る
% mysql -u root
# アカウント作成
mysql> create user 'ユーザー名'@'localhost' identified by 'パスワード';

# データベース作成('golang'というDBを作成)
mysql> create database golang;

# 作成したアカウントに権限を追加
mysql> GRANT ALL ON golang.* TO 'ユーザー名'@'localhost';

mysql> exit;

使用SequelAce可以轻松操作MySQL。下载SequelAce。

使用Golang进行MySQL数据的添加、更新和获取

MySQL方
MySQL一方
MySQL的角度

数据表名为“users”。

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| golang             |  <- 作成
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+

mysql> use golang;
mysql> show tables;
+------------------+
| Tables_in_golang |
+------------------+
| users            |
+------------------+

mysql> desc users;
+-------------+--------------+------+-----+---------+----------------+
| Field       | Type         | Null | Key | Default | Extra          |
+-------------+--------------+------+-----+---------+----------------+
| id          | int unsigned | NO   | PRI | NULL    | auto_increment |
| name        | varchar(255) | YES  |     | NULL    |                |
| age         | int          | YES  |     | NULL    |                |
| created_at  | timestamp    | YES  |     | NULL    |                | <- 必要
| updated_at  | timestamp    | YES  |     | NULL    |                | <- 必要
| deleted_at  | timestamp    | YES  |     | NULL    |                | <- 必要
+-------------+--------------+------+-----+---------+----------------+
スクリーンショット 2021-04-04 13.15.48.png

使用SequelAce创建如此的Gorm时,需要预先创建[created_at,updated_at,deleted_at]。

Go语言方面

我尝试使用gorm来操作MySQL,但遇到了困难。
虽然不太清楚具体原因,但可能是命名出错了。
需要注意大写、小写、复数、单数的命名规范。
在MySQL中是”users”,但在Golang中调用时应为”User”。
在MySQL中是”name”,但在Golang中调用时应为”Name”。
需要特别注意这些细节。

由于未进行确认动作检查,可能会出现错误。

package routing

import (
    "fmt"
    "github.com/labstack/echo"
    "github.com/jinzhu/gorm"
    _ "github.com/jinzhu/gorm/dialects/mysql"
)

type User struct {
    gorm.Model
    //`json:"--"`はリクエストボディに指定する名前
    Name                string `json:"name"`
    Age                 int    `json:"age"`
}


func (u User) String() string {
    return fmt.Sprintf("Name:%s \n Age:%d \n ",
        u.Name,
        u.Age)
}

// ユーザーを登録,更新
func BaseAPI_user() echo.HandlerFunc {
    return func(c echo.Context) error {
        db := databases.GormConnect()
        defer db.Close()

        //リクエストボディ
        user := new(User)

        user1 := User{
            Name:     user.Name,
            Age:      user.Age,}

        // 追加
        insertUsers := []User{user1}
        insert(insertUsers, db)

        // 更新
        update(user1, db)

        // 検索(年齢一致)
        var count = search(user.Age, db)

        return c.JSON(200, count)
    }
}

func insert(users []User, db *gorm.DB) {
    for _, user := range users {
        db.NewRecord(user)
        db.Create(&user)
    }
}

func update(users User, db *gorm.DB) {
    var user User
    db.Model(&user).Where("id = ?", 1).Update(map[string]interface{}{"name": users.Name, "Age": users.Age})
}


func search(age int, db *gorm.DB) ([]User) {
    var user []User
    db.Raw("SELECT * FROM users WHERE age = ? ", age).Scan(&user)

    return user
}

// SQLConnect DB接続
func GormConnect() (database *gorm.DB) {
    // パスワード等を.envファイルから読み取る
    // program > go > .env
    err := godotenv.Load(fmt.Sprintf("../%s.env", os.Getenv("GO_ENV")))
    if err != nil {
        panic(err.Error())
    } else {
        fmt.Println("env読み取り成功")
    }

    DBMS := "mysql"                   // MySQL
    PROTOCOL := "tcp(localhost:3306)" // db:3306
    DBNAME := ""    // テーブル名
    USER := ""      // MySQLユーザー名
    PASS := ""  // パスワード

    CONNECT := USER + ":" + PASS + "@" + PROTOCOL + "/" + DBNAME + "?charset=utf8&parseTime=true&loc=Asia%2FTokyo"
    db, err := gorm.Open(DBMS, CONNECT)
    if err != nil {
        panic(err.Error())
    } else {
        fmt.Println("DB接続成功")
    }
    return db
}
bannerAds