当前位置:网站首页>Initialize MySQL Gorm through yaml file

Initialize MySQL Gorm through yaml file

2022-06-23 03:21:00 Trespass

Introduce

Through a complete example , Introduce how to use YAML file , Easy initialization gorm.

We will use rk-boot To initialize the .

GORM It is well encapsulated , What's the use of this ?

rk-boot/database/mysql No, right gorm Conduct 2 Secondary packaging . Instead, it provides a way to pass YAML initialization gorm Methods . We hope that in this way , simplify gorm Initialization process , Including logs , Instance management .

meanwhile , Through one YAML Documents represent dependencies in microservices , It will be more concise than reading the code .

install

We install two dependencies , One is MySQL starter , The other is gin-gonic/gin Web Frame starter .

The reason for installing gin-gonic/gin , It's because we'll create one that has API Of MySQL CRUD Example .

go get github.com/rookie-ninja/rk-boot/database/mysql
go get github.com/rookie-ninja/rk-boot/gin

Quick start

Please refer to Complete example

We create a simple microservice , It includes the following API.

  • GET /v1/user, List all user information
  • GET /v1/user/:id, Get user information
  • PUT /v1/user, Create user
  • POST /v1/user/:id, Update user information
  • DELETE /v1/user/:id, Delete user

1. establish boot.yaml

boot.yaml The file will tell rk-boot How to start a process . There are two functions in the example .

  • gin: tell rk-boot start-up 8080 port
  • mySql: tell rk-boot How to initialize gorm, And create links , Configuration log .
---
gin:
  - name: user-service
    port: 8080
    enabled: true
mySql:
  - name: user-db                     # Required
    enabled: true                     # Required
    locale: "*::*::*::*"              # Required
    addr: "localhost:3306"            # Optional, default: localhost:3306
    user: root                        # Optional, default: root
    pass: pass                        # Optional, default: pass
    database:
      - name: user                    # Required
        autoCreate: true              # Optional, create database automatically, default: false
#        dryRun: false                # Optional, default: false
#        params: []                   # Optional, default: ["charset=utf8mb4","parseTime=True","loc=Local"]
#    logger:
#      level: warn                    # Optional, default: warn
#      encoding: json                 # Optional, default: console
#      outputPaths: [ "mysql/log" ]   # Optional, default: []

2. establish main.go

stay main.go Function , We realized two things .

  • userDb.AutoMigrate(&User{}): Give Way gorm Automatically create User surface .
  • stay gin.Router Register in API.
// Copyright (c) 2021 rookie-ninja
//
// Use of this source code is governed by an Apache-style
// license that can be found in the LICENSE file.
package main

import (
	"context"
	"github.com/gin-gonic/gin"
	"github.com/rookie-ninja/rk-boot"
	"github.com/rookie-ninja/rk-boot/gin"
	"github.com/rookie-ninja/rk-db/mysql"
	"gorm.io/gorm"
	"net/http"
	"strconv"
	"time"
)

var userDb *gorm.DB

func main() {
	boot := rkboot.NewBoot()

	boot.Bootstrap(context.TODO())

	// Auto migrate database and init global userDb variable
	mysqlEntry := rkmysql.GetMySqlEntry("user-db")
	userDb = mysqlEntry.GetDB("user")
	if !userDb.DryRun {
		userDb.AutoMigrate(&User{})
	}

	// Register APIs
	ginEntry := rkbootgin.GetGinEntry("user-service")
	ginEntry.Router.GET("/v1/user", ListUsers)
	ginEntry.Router.GET("/v1/user/:id", GetUser)
	ginEntry.Router.PUT("/v1/user", CreateUser)
	ginEntry.Router.POST("/v1/user/:id", UpdateUser)
	ginEntry.Router.DELETE("/v1/user/:id", DeleteUser)

	boot.WaitForShutdownSig(context.TODO())
}

// *************************************
// *************** Model ***************
// *************************************

type Base struct {
	CreatedAt time.Time      `yaml:"-" json:"-"`
	UpdatedAt time.Time      `yaml:"-" json:"-"`
	DeletedAt gorm.DeletedAt `yaml:"-" json:"-" gorm:"index"`
}

type User struct {
	Base
	Id   int    `yaml:"id" json:"id" gorm:"primaryKey"`
	Name string `yaml:"name" json:"name"`
}

func ListUsers(ctx *gin.Context) {
	userList := make([]*User, 0)
	res := userDb.Find(&userList)

	if res.Error != nil {
		ctx.JSON(http.StatusInternalServerError, res.Error)
		return
	}
	ctx.JSON(http.StatusOK, userList)
}

func GetUser(ctx *gin.Context) {
	uid := ctx.Param("id")
	user := &User{}
	res := userDb.Where("id = ?", uid).Find(user)

	if res.Error != nil {
		ctx.JSON(http.StatusInternalServerError, res.Error)
		return
	}

	if res.RowsAffected < 1 {
		ctx.JSON(http.StatusNotFound, "user not found")
		return
	}

	ctx.JSON(http.StatusOK, user)
}

func CreateUser(ctx *gin.Context) {
	user := &User{
		Name: ctx.Query("name"),
	}

	res := userDb.Create(user)

	if res.Error != nil {
		ctx.JSON(http.StatusInternalServerError, res.Error)
		return
	}
	ctx.JSON(http.StatusOK, user)
}

func UpdateUser(ctx *gin.Context) {
	uid := ctx.Param("id")
	user := &User{
		Name: ctx.Query("name"),
	}

	res := userDb.Where("id = ?", uid).Updates(user)

	if res.Error != nil {
		ctx.JSON(http.StatusInternalServerError, res.Error)
		return
	}

	// get user
	userDb.Where("id = ?", uid).Find(user)

	ctx.JSON(http.StatusOK, user)
}

func DeleteUser(ctx *gin.Context) {
	uid, _ := strconv.Atoi(ctx.Param("id"))
	res := userDb.Delete(&User{
		Id: uid,
	})

	if res.Error != nil {
		ctx.JSON(http.StatusInternalServerError, res.Error)
		return
	}
	ctx.String(http.StatusOK, "success")
}

3. start-up main.go

$ go run main.go

2022-01-20T01:38:21.698+0800    INFO    boot/gin_entry.go:596   Bootstrap ginEntry      {"eventId": "7cbf2a59-ebae-46a1-b8a9-595aeab6c774", "entryName": "user-service"}
------------------------------------------------------------------------
endTime=2022-01-20T01:38:21.699029+08:00
startTime=2022-01-20T01:38:21.698951+08:00
elapsedNano=78296
timezone=CST
ids={"eventId":"7cbf2a59-ebae-46a1-b8a9-595aeab6c774"}
app={"appName":"rk","appVersion":"","entryName":"user-service","entryType":"Gin"}
env={"arch":"amd64","az":"*","domain":"*","hostname":"lark.local","localIP":"10.8.0.2","os":"darwin","realm":"*","region":"*"}
payloads={"ginPort":8080}
error={}
counters={}
pairs={}
timing={}
remoteAddr=localhost
operation=Bootstrap
resCode=OK
eventStatus=Ended
EOE
2022-01-20T01:38:21.699+0800    INFO    mysql/boot.go:331       Bootstrap mysql entry   {"entryName": "user-db", "mySqlUser": "root", "mySqlAddr": "localhost:3306"}
2022-01-20T01:38:21.699+0800    INFO    mysql/boot.go:406       Creating database [user]
2022-01-20T01:38:21.718+0800    INFO    mysql/boot.go:428       Creating database [user] successs
2022-01-20T01:38:21.718+0800    INFO    mysql/boot.go:431       Connecting to database [user]
2022-01-20T01:38:21.726+0800    INFO    mysql/boot.go:443       Connecting to database [user] success

4. verification

4.1 Create user

$ curl -X PUT "localhost:8080/v1/user?name=rk-dev"
{"id":2,"name":"rk-dev"}

4.2 Update user

$ curl -X POST "localhost:8080/v1/user/2?name=rk-dev-updated"
{"id":2,"name":"rk-dev-updated"}

4.3 List all users

$ curl -X GET localhost:8080/v1/user
[{"id":2,"name":"rk-dev-updated"}]

4.4 Get user information

$ curl -X GET localhost:8080/v1/user/2
{"id":2,"name":"rk-dev-updated"}

4.5 Delete user

$ curl -X DELETE localhost:8080/v1/user/2
success

YAML Options

The user can go through YAML Initialize multiple at the same time gorm example . Please use a different name .

name

Required

description

type

default value

mysql.name

Required

The name of entry

string

MySql

mysql.enabled

Required

Enable entry or not

bool

false

mysql.locale

Required

See locale description bellow

string

""

mysql.description

Optional

Description of echo entry.

string

""

mysql.user

Optional

MySQL username

string

root

mysql.pass

Optional

MySQL password

string

pass

mysql.protocol

Optional

Connection protocol to MySQL

string

tcp

mysql.addr

Optional

MySQL remote address

string

localhost:3306

mysql.database.name

Required

Name of database

string

""

mysql.database.autoCreate

Optional

Create DB if missing

bool

false

mysql.database.dryRun

Optional

Run gorm.DB with dry run mode

bool

false

mysql.database.params

Optional

Connection params

[]string

"charset=utf8mb4","parseTime=True","loc=Local"

mysql.logger.encoding

Optional

Log encoding type, json & console are available options

string

console

mysql.logger.outputPaths

Optional

Output paths of logger

[]string

stdout

mysql.logger.level

Optional

Logger level, options: silent, error, warn, info

string

warn

Locale usage

Locale Option is to pass the environment variable , Distinguish between different YAML Entry And the introduction of .

RK use <realm>::<region>::<az>::<domain> to distinguish different environment.
Variable of <locale> could be composed as form of <realm>::<region>::<az>::<domain>
- realm: It could be a company, department and so on, like RK-Corp.
         Environment variable: REALM
         Eg: RK-Corp
         Wildcard: supported

- region: Please see AWS web site: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-regions-availability-zones.html
          Environment variable: REGION
          Eg: us-east
          Wildcard: supported

- az: Availability zone, please see AWS web site for details: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-regions-availability-zones.html
      Environment variable: AZ
      Eg: us-east-1
      Wildcard: supported

- domain: Stands for different environment, like dev, test, prod and so on, users can define it by themselves.
          Environment variable: DOMAIN
          Eg: prod
          Wildcard: supported

How it works?
First, we will split locale with "::" and extract realm, region, az and domain.
Second, get environment variable named as REALM, REGION, AZ and DOMAIN.
Finally, compare every element in locale variable and environment variable.
If variables in locale represented as wildcard(*), we will ignore comparison step.

Example:
# let's assuming we are going to define DB address which is different based on environment.
# Then, user can distinguish DB address based on locale.
# We recommend to include locale with wildcard.
---
DB:
  - name: redis-default
    locale: "*::*::*::*"
    addr: "192.0.0.1:6379"
  - name: redis-default
    locale: "*::*::*::test"
    addr: "192.0.0.1:6379"
  - name: redis-default
    locale: "*::*::*::prod"
    addr: "176.0.0.1:6379"
原网站

版权声明
本文为[Trespass ]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/01/202201200250213969.html