Go language operation database and its general operation

Posted by DssTrainer on Fri, 11 Feb 2022 02:18:12 +0100

Go MySQL operation

Install: go get - u GitHub com/go-sql-driver/mysql

The operation database driver of GO language supports connection pool and is a standard library for concurrency security. There is no specific implementation, but lists the specific contents of some third-party libraries that need to be implemented

//Successfully connected to MySQL for the first time
package main

import (
    "database/sql"
    _ "github.com/go-sql-driver/mysql"   // _ Want to initialize when init()
    "log"
)

func main() {
    // The root user name 1qa2ws3ed is the IP: Port cause library name behind the password
    dsn := "root:1qa2ws3ed@tcp(127.0.0.1:3306)/gouse"
    db, err := sql.Open("mysql", dsn)
    if err != nil {
        panic(err)
    }
    // ping is an attempt to connect to the MySQL database

    if err = db.Ping(); err != nil{
        panic(err)
    }
    log.Fatalln("Mysql Database connection succeeded")

}
  • Go calls MySQL and encapsulates it into a function
package main

import (
    "database/sql"
    "encoding/json"
    "fmt"
    _ "github.com/go-sql-driver/mysql"
)

var db *sql.DB

func InitDB() (err error) {
    dsn := "root:1qa2ws3ed@tcp(127.0.0.1:3306)/gouse"

    db, err = sql.Open("mysql", dsn)
    CheckErr(err)

    err = db.Ping()
    CheckErr(err)
    fmt.Println("Database connection succeeded...")
    // Set the maximum number of connections to the database connection pool
    db.SetConnMaxLifetime(10)

    //Set the maximum number of idle connections
    db.SetMaxIdleConns(5)

    return
}

type data struct {
    Username string `json:"username"`
    Password string `json:"password"`
}


func main()  {
    err := InitDB()
    CheckErr(err)

    query, err := db.Query("select username, password from test")
    CheckErr(err)

    for query.Next(){
        line := data{}
        // The scan method must be called when querying data. If the scan connection channel is not used, the connection cannot be released  
        _ = query.Scan(&line.Username, &line.Password)
        fmt.Println(line)
        dataDic := map[string]string{
            "username": line.Username,
            "password": line.Password,
        }
        marshal, _ := json.Marshal(dataDic)
        fmt.Println(string(marshal))
    }


}

func CheckErr(err error) {
    if err != nil {
        fmt.Println(err)
        panic(err)
    }
}
  • GO - addition, deletion, modification and query of MySQL
package main

import (
    "database/sql"
    "encoding/json"
    "fmt"
    "time"

    _ "github.com/go-sql-driver/mysql"
)

var db *sql.DB

// InitDB database connection initialization
func InitDB() (err error) {
    dsn := "root:1qa2ws3ed@tcp(127.0.0.1:3306)/gouse"

    db, err = sql.Open("mysql", dsn)
    CheckErr(err)

    err = db.Ping()
    CheckErr(err)
    fmt.Println("Database connection succeeded...")
    // Set the maximum number of connections to the database connection pool
    db.SetConnMaxLifetime(10)

    //Set the maximum number of idle connections
    db.SetMaxIdleConns(5)

    return

}

type data struct {
    Username string `json:"username"`
    Password string `json:"password"`
}

// SelectQuery query function
func SelectQuery() {
    sqlStr := "select username, password from test where id > ?"
    query, err := db.Query(sqlStr, 1)
    CheckErr(err)
    defer query.Close()

    fmt.Printf("It's Beijing time %s , Have you made progress today?\n", time.Now().Format("2006-01-02 15:04:05"))

    for query.Next() {
        line := data{}
        // The scan method must be called when querying data. If the scan connection channel is not used, the connection cannot be released
        _ = query.Scan(&line.Username, &line.Password)
        //fmt.Println(line)
        dataDic := map[string]string{
            "username": line.Username,
            "password": line.Password,
        }
        marshal, _ := json.Marshal(dataDic)
        fmt.Printf("The queried data is %s\n", string(marshal))
    }
}

// InsertQuery insert data
func InsertQuery() {
    // sql statement
    sqlStr := `insert into test (username,password) values ("kuQi", "123qwe")`
    result, err := db.Exec(sqlStr)
    CheckErr(err)
    id, err := result.LastInsertId()
    CheckErr(err)
    fmt.Printf("Of successfully inserted data id by %v", id)
}

// UpdateQuery update data function
func UpdateQuery(dataField string, user string) {
    sqlStr := `update test set password=? where username=?`
    result, err := db.Exec(sqlStr, dataField, user)
    CheckErr(err)
    rowsAffected, err := result.RowsAffected()
    CheckErr(err)
    fmt.Printf("Updated field id by%d\n", rowsAffected)

}

// DeleteQuery delete
func DeleteQuery(id int) {
    sqlStr := `delete from test where id=?`
    result, err := db.Exec(sqlStr, id)
    CheckErr(err)
    rowsAffected, err := result.RowsAffected()
    CheckErr(err)
    if rowsAffected == 0 {
        fmt.Printf("There are no matches to delete id=%d data", id)
        return
    }
    fmt.Printf("Delete database id by%d", id)

}

//CheckErr exception capture function
func CheckErr(err error) {
    if err != nil {
        fmt.Println(err)
        panic(err)
    }
}

// Main main function is the entry of all functions
func main() {
    err := InitDB()
    CheckErr(err)

    //InsertQuery()
    UpdateQuery("hahaGolang123", "kuQi")
    SelectQuery()
    DeleteQuery(5)
}
  • Preprocessing of MySQL
What is preprocessing?
ordinary SQL Statement execution process:
    1.Client pair SQL Statement to replace the placeholder and get the complete SQL sentence
    2.Client send complete SQL Statement to MySQL Server
    3.MySQL The server performs a complete SQL Statement and returns the result to the terminal

Execution process of preprocessing
    1.First SQL The statement is split into two parts, SQL Statement part and parameter part
    2.First SQL Statement part sent to MySQL On the server side SQL Pretreatment
    3.Then the parameter part is sent to MySQL Server side, MySQL yes SQL Statement splicing
    4.MySQL The server performs a complete SQL Statement returns the result

Why pretreatment?
  1.In order to optimize MySQL Server repeat SQL Methods. The performance of the server can be executed. The server can compile in advance and execute multiple times at a time, so as to save the cost of subsequent repeated compilation
  2.And avoid SQL injection
  • Go implements MySQL preprocessing
// The prepare method now sends the SQL to the MySQL server and returns a ready state for subsequent queries and commands. The return value can execute multiple queries and commands at the same time; Commands are SQL statements
// PrepareInsert preprocesses the execution of insert statements
func PrepareInsert() {

    defer wg.Done()
    sqlStr := `insert into test (username, password) values (?, ?)`
    // -Preprocessing stmt is to pass parameters directly after the compiled sql statement
    stmt, err := db.Prepare(sqlStr)
    var u1 = uuid.Must(uuid.NewV4())
    CheckErr(err)
    defer stmt.Close()
    i := rand.Int()

    username := fmt.Sprintf("yonghuming%d", i)
    result, err := stmt.Exec(username, u1.String()[:10])
    CheckErr(err)
    rowsAffected, err := result.LastInsertId()
    CheckErr(err)
    fmt.Printf("Successfully inserted id=%d Data bar\n", rowsAffected)
}
  • MySQL transaction operation in Go language
// go language uses the following three methods to realize the transaction operation in MySQL and start the transaction
func (db *DB) Begin()(*Tx, error)

// Commit transaction is equivalent to conn.commit() in Python
func (tx *Tx) Commit() error   

// Rollback transaction
func (tx *Tx) Rollback() error








package main

import (
    "database/sql"
    "fmt"

    _ "github.com/go-sql-driver/mysql"
)

var db *sql.DB

type data struct {
    Username string `json:"username"`
    Password string `json:"password"`
}

// InitDB database connection initialization
func InitDB() (err error) {
    dsn := "root:1qa2ws3ed@tcp(127.0.0.1:3306)/gouse"

    db, err = sql.Open("mysql", dsn)
    CheckErr(err)

    err = db.Ping()
    CheckErr(err)
    fmt.Println("Database connection succeeded...")
    // Set the maximum number of connections to the database connection pool
    db.SetMaxOpenConns(100)

    //Set the maximum number of idle connections
    db.SetMaxIdleConns(5)

    return

}

//CheckErr exception capture function
func CheckErr(err error) {
    if err != nil {
        fmt.Println(err)
        panic(err)
    }
}

// Transaction operation of MySQL transon
func TranSaCtIon() {
    // Open transaction
    tx, err := db.Begin()
    CheckErr(err)

    // Perform multiple SQL operations
    sqlStr := `update test set id=id+100000 where password=?`
    result, err := tx.Exec(sqlStr, "07f70f7e-4")
    CheckErr(err)
    id, err := result.LastInsertId()
    if err != nil {
        // Statement rollback
        err := tx.Rollback()
        fmt.Println("Transaction rollback")
        CheckErr(err)

    }
    fmt.Printf("Modified id by%d\n", id)

}

func main() {
    err := InitDB()
    CheckErr(err)
    TranSaCtIon()
}

  • sqlx usage

The third-party library sqlx can simplify the operation and improve the development efficiency

Install go get GitHub com/jmoiron/sqlx

package main

import (
    "fmt"

    _ "github.com/go-sql-driver/mysql"
    "github.com/jmoiron/sqlx"
)

var db *sqlx.DB

// InitDB database initialization
func InitDB() (err error) {
    dsn := "root:1qa2ws3ed@tcp(127.0.0.1:3306)/gouse"
    db, err = sqlx.Connect("mysql", dsn)
    CheckErr(err)
    db.SetMaxOpenConns(50)
    db.SetMaxIdleConns(10)
    fmt.Println("goUse Database connection succeeded")
    return
}

//CheckErr exception capture function
func CheckErr(err error) {
    if err != nil {
        fmt.Println(err)
        panic(err)
    }
}

func main() {
    err := InitDB()
    CheckErr(err)
}


Compared with the native sql library, sqlx has the advantage that it needs the next scan callback to get the results when querying

sqlx query only needs to define a stored variable, and then automatically put the queried value into the variable

package main

import (
    "encoding/json"
    "fmt"

    _ "github.com/go-sql-driver/mysql"
    "github.com/jmoiron/sqlx"
)

var db *sqlx.DB

type user struct {
    ID       int    `json:"id"`
    Username string `json:"username"`
    Password string `json:"password"`
}

// InitDB database initialization
func InitDB() (err error) {
    dsn := "root:1qa2ws3ed@tcp(127.0.0.1:3306)/gouse"
    // Connect is the simultaneous connection of DB Ping
    db, err = sqlx.Connect("mysql", dsn)
    CheckErr(err)
    db.SetMaxOpenConns(50)
    db.SetMaxIdleConns(10)
    fmt.Println("goUse Database connection succeeded")
    return
}

// SelectDB method for querying single data
func SelectDB() {
    sqlStr := `select * from test where id=?`
    var data user
    _ = db.Get(&data, sqlStr, 990)
    //CheckErr(err)
    fmt.Printf("%#v\n", data)
    marshal, err := json.Marshal(data)
    CheckErr(err)
    fmt.Println(string(marshal))
}

// ManySelect query multiple data methods
func ManySelect() {
    sqlStr := `select * from test where id < ?`
    var dataList []user
    err := db.Select(&dataList, sqlStr, 1000)
    CheckErr(err)
    //fmt.Println(dataList)
    marshal, err := json.Marshal(dataList)
    CheckErr(err)
    fmt.Println(string(marshal))
}

//CheckErr exception capture function
func CheckErr(err error) {
    if err != nil {
        fmt.Println(err)
        panic(err)
    }
}

func main() {
    err := InitDB()
    CheckErr(err)
    SelectDB()
    ManySelect()

}

Go operation Redis

Install go get - u GitHub com/go-redis/redis

package main

import (
    "fmt"

    "github.com/go-redis/redis"
)

var redisDB *redis.Client

// InitRedisDB redis database initialization
func InitRedisDB() (err error) {

    redisDB = redis.NewClient(&redis.Options{
        Addr:     "127.0.0.1:6379",
        Password: "",
        DB:       0,
    })
    _, err = redisDB.Ping(redisDB.Context()).Result()
    CheckErr(err)
    fmt.Println("redis Connection successful")
    return
}

//CheckErr exception capture function
func CheckErr(err error) {
    if err != nil {
        fmt.Println(err)
        panic(err)
    }
}

func main() {
    _ = InitRedisDB()
}
set(key, value): The name in the database is key of string Assign value value
get(key): Returns the name in the database key of string of value
getset(key, value): Give the name key of string Give the last value
mget(key1, key2,..., key N): Return multiple in the library string of value
setnx(key, value): add to string,Name is key,Value is value
setex(key, time, value): Add to Library string,Set expiration time time
mset(key N, value N): Batch setting multiple string Value of
msetnx(key N, value N): If all names are key i of string None of them exist
incr(key): Name is key of string Add 1 operation
incrby(key, integer): Name is key of string increase integer
decr(key): Name is key of string Minus 1 operation
decrby(key, integer): Name is key of string reduce integer
append(key, value): Name is key of string Added value of value
substr(key, start, end): Return as name key of string of value Substring of

NSQ distributed message queue

NSQ is a popular distributed message queue. The following is how NSQ and GO language operate NSQ

NSQ is an open source real-time distributed memory message queue written in GO language. Its performance is very excellent. NSQ has the following advantages:

​ 1.NSQ advocates distributed and diffused topology, without single point of failure, supports fault tolerance and high availability, and provides reliable message delivery guarantee

​ 2.NSQ supports scale out without any centralized agents

​ 3.NSQ is easy to configure and deploy and has a built-in management interface

Install go get - u GitHub com/nsqio/go-nsq

Context

stay Go HTTP Wrapped server In, each request corresponds to a response, and the request processing function usually starts additional processing goroutine Used to access back-end services, such as databases and rpc Service, which is used to process a request goroutine It is usually necessary to access some specific data related to the request, such as terminal authentication information and authentication token,Request and deadline. When a request is cancelled or timed out, all the data used to process the request goroutine Should exit quickly before the system can release these goroutine

How to end goroutine gracefully and release resources

// Channel version
package main

import (
    "fmt"
    "sync"
    "time"
)

var wg sync.WaitGroup

func worker(exitChan <-chan struct{}) {
    defer wg.Done()
Test:
    for {
        fmt.Println("worker")
        time.Sleep(time.Second)
        select {
        case <-exitChan:
            break Test
        default:
        }

    }

}

func main() {
    wg.Add(1)
    c := make(chan struct{})

    go worker(c)
    time.Sleep(10 * time.Second)
    c <- struct{}{}
    close(c)
    wg.Wait()
    fmt.Println("Over")

}
// Context version
package main

import (
    "context"
    "fmt"
    "sync"
    "time"
)

var wg sync.WaitGroup

func worker(ctx context.Context) {
    defer wg.Done()
Test:
    for {
        fmt.Println("worker")
        time.Sleep(time.Second)
        select {
        case <-ctx.Done():
            break Test
        default:
        }

    }

}

func main() {
    wg.Add(1)
    ctx, cancelFunc := context.WithCancel(context.Background())

    go worker(ctx)
    time.Sleep(10 * time.Second)

    cancelFunc()
    wg.Wait()
    fmt.Println("Over")

}

If goroutine opens a new goroutine, you only need to pass ctx into the new goroutine

Background() and TODO()

go has two built-in functions: Background() and TUDO(). These two functions return a background and todo that implement the context interface respectively At the beginning of our code, these two built-in context objects are used as the top-level part context to derive more sub context objects.

Background () is mainly used for main function, initialization and code testing. It is the top-level context of the tree structure of context, that is, context.

He doesn't know what he can do yet?

Precautions for using context

  • It is recommended to display and pass context with parameters
  • The function method with context as the parameter should take context as the first parameter
  • When passing context to a function, don't nil. If you don't know what to pass, use context TODO()
  • context is concurrent and safe, and can be freely passed in multiple goroutine s

log standard library

The log package defines the logger type, which provides some methods to format the output. This package also provides a predefined standard logger, which can be used by calling the functions Print series, fatal series and panic series. It is easier to use than the self created logger object.

package main

import "log"

func main() {
    log.Println("This is the first work log")

    v := "THIS is worker log"
    log.Printf("%#v\n", v)
    // After Fatal writes the value to the message, execute exit(1)
    log.Fatal("After writing 10000 lines of code, I won't execute it")

    // You can log Panic throws an exception after writing the log
    log.Panic("test panic Log of")

}
  • flag option (log output content setting)
log The standard library provides the following flag Options, which are a series of defined constants.
const (
    Ldate = 1 << iota
  Ltime
  Lmicroseconds
  Llongfile
  Lshortfile
  LUTC
  LstdFlags = Ldate | Ltime
)



package main
import "log"
func main() {
    // Set default additional content 
        log.SetFlags(log.Llongfile | log.Ltime)
    // Set log prefix
        log.SetPrefix("[go_log] ")
        log.Println("Test log")

}
output>>>
[go_log] 19:02:14 /Users/mac/GolandProjects/src/day02/go_log library/main.go:19: Test log

  • Configure log output location

The setoutput function is used to set the output destination of the logger. The default is standard error output

package main

import (
    "log"
    "os"
)

func main() {

    file, err := os.OpenFile("test.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
    if err != nil {
        log.Panic("File open failed")
    }
  // If the write file log is set, the contents will not be printed to the terminal
    log.SetOutput(file)
    log.SetFlags(log.Llongfile | log.Ltime)
    log.SetPrefix("[go_log] ")
    log.Println("Test log")

}
We can define one init The initialization function will log All configured, so it's more standardized

Use of third-party logrus

logrus is a GO structured logger, which is fully compatible with the above logger standard library

Install logrusgo get GitHub com/sirupsen/logrus

package main

import (
    log "github.com/sirupsen/logrus"
)

func main() {
    log.WithFields(log.Fields{
        "animals": "dog",
        "time":    log.FieldKeyTime,
    }).Info("What is this")

}
  • log level

Trace,debug,info,warning,error,fatal,panic

    log.Trace("track?")
    log.Debug("Debug?")
    log.Info("information")
    log.Warn("Warning?")
    log.Error("Something failed but I'm not quitting.")
    // After recording the log, the system will call OS Exit(1) 
    log.Fatal("Bye.")
    // panic() will be called after logging 
    log.Panic("I'm bailing.")
  • Logging
package main

import (
    "os"
    "time"

    log "github.com/sirupsen/logrus"
)

func main() {
    file, err := os.OpenFile("logrustest.log", os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0644)
    if err != nil {
        log.Panicln(err)
    }
    log.SetOutput(file)
    for i := 0; i < 100; i++ {
        log.WithFields(log.Fields{
            "animals": "dog",
            "Countey": "China",
            "City":    "BeiJing",
        }).Info("What is this")
        time.Sleep(time.Second)
    }

    log.Trace("track?")
    log.Info("information")
    log.Warn("Warning?")
    // Setting the log level will record the level above info (warn error fatal panic)
    log.SetLevel(log.InfoLevel)

}

>>>result
time="2021-02-04T12:00:15+08:00" level=info msg="What is this" City=BeiJing Countey=China animals=dog
time="2021-02-04T12:00:17+08:00" level=info msg="What is this" City=BeiJing Countey=China animals=dog
time="2021-02-04T12:00:18+08:00" level=info msg="What is this" City=BeiJing Countey=China animals=dog
time="2021-02-04T12:00:19+08:00" level=info msg="What is this" City=BeiJing Countey=China animals=dog

In addition to the related logs added by withfield and withfields, there are also some log fields added by default

Timestamp of time logging msg logging information level logging level

  • Log format

logrus has two kinds of log formatter built in

logrus.TextFormatter logrus.JSONFormatter

log.SetFormatter(&log.JSONFormatter{})
  • Tracking function
    log.SetReportCaller(true)
    This will record which file and which line, but it is not a special requirement. You don't need to open this because it will increase the performance overhead

Topics: Go