GO web 開發 實戰三,資料庫預處理

阿兵雲原生發表於2023-02-08

上一篇文章我們進行了資料操作,都是使用佔位符的方式來操作的

我們們其實可以使用 mysql 預處理的方式來操作這些

那麼我們一起來看看什麼是已處理呢?

什麼是預處理?

瞭解什麼是預處理,我們可以來對比一下,普通的 sql 語句執行過程和 預處理的執行過程

普通 sql 語句執行過程:

  • 客戶端對 SQL 語句進行 佔位符 替換得到完整的 sql 語句
  • 客戶端傳送完整 sql 語句到 mysql 服務端
  • mysql 服務端執行完整的 sql 語句並將結果返回給客戶端

預處理執行過程:

  • 把 sql 語句分成兩部

    • 命令部分
    • 資料部分
  • 先把命令部分傳送給 mysql 服務端,mysql 服務端進行 sql 預處理
  • 然後把資料部分傳送給 mysql 服務端, mysql 服務端對 sql 語句進行佔位符替換
  • mysql 服務端執行完整的 sql 語句並將結果返回給客戶端

透過步驟和流程,我們大概知道預處理肯定比普通的 sql 執行快

那麼預處理有啥好處?

  • 最佳化 mysql 伺服器重複執行 sql 的方法,可以提升伺服器效能,提前讓伺服器編譯,一次編譯多次
    執行,節省後續編譯的成本
  • 避免 sql 注入的問題
//預處理 插入資料操作
func prepareInfo(db *sql.DB) {
    sqlInfo := "insert into user (name,age)values(?,?)"

    stmt, err := db.Prepare(sqlInfo)
    if err != nil {
        fmt.Println("Exec err : ", err)
        return
    }

    ret, err := stmt.Exec("花豬2", 28)
    if err != nil {
        fmt.Println("stmt Exec err : ", err)
        return
    }
    ret, err = stmt.Exec("花豬3", 28)
    if err != nil {
        fmt.Println("stmt Exec err : ", err)
        return
    }

    rows, err := ret.RowsAffected()
    if err != nil {
        fmt.Println("stmt Exec err : ", err)
        return
    }
    fmt.Println("rows = ", rows)

}

Go實現 MySQL 的事務

  • 開啟事務處理,會有回滾機制,全部成功了,且提交成功,才算事務處理成功
  • func (db *DB) Begin() (*Tx, error) 事務開始
  • func (tx *Tx) Commit() error 事務提交
  • func (tx *Tx) Rollback() error 事務回滾

    func trasaction(db *sql.DB) {
    
        //開啟一個事務
    
        tx, err := db.Begin()
        if err != nil {
            if tx != nil {
                tx.Rollback()
            }
            fmt.Printf("Begin err :%v", err)
            return
        }
    
        sqlStr := "update user set name='xxx' where id=?"
        _, err = tx.Exec(sqlStr, 9)
        if err != nil {
            if tx != nil {
                tx.Rollback()
            }
            fmt.Printf("Exec err :%v", err)
            return
        }
    
        sqlStr = "update user set name='xxx' where id=?"
        _, err = tx.Exec(sqlStr, 6)
        if err != nil {
            if tx != nil {
                tx.Rollback()
            }
            fmt.Printf("Exec err :%v", err)
            return
        }
    
        //提交事務
        err = tx.Commit()
        if err != nil {
            if tx != nil {
                tx.Rollback()
            }
            fmt.Printf("Commit err :%v", err)
            return
        }
    
        fmt.Println("commit success ")
    }

sqlx使用

我們們還可以使用第三方庫 sqlx

  • 安裝第三方庫 sqlx ,go get github.com/jmoiron/sqlx
  • 第三方庫可以提交高開發效率,簡化開發操作

    package main
    
    import (
        "fmt"
        "github.com/jmoiron/sqlx"
        _ "github.com/go-sql-driver/mysql" // 註釋掉後異常 _ 呼叫初始化函式
    )
    
    var db *sqlx.DB
    
    func insertInfo() {
    
        sqlStr := "insert into user(name,age)values(?,?)"
        res, err := db.Exec(sqlStr, "xxx", 2)
        if err != nil {
            fmt.Printf("Exec err : %v", err)
            return
        }
        id, err := res.LastInsertId()
        if err != nil {
            fmt.Printf("LastInsertId err : %v", err)
            return
        }
        fmt.Printf("id == %d", id)
    
        rows, err := res.RowsAffected()
        if err != nil {
            fmt.Printf("RowsAffected err : %v", rows)
            return
        }
        fmt.Printf("rows == %d", rows)
        return
    
    }
    
    func main() {
    
        var err error
        dsn := "root:123456@tcp(127.0.0.1:3306)/go_test?charset=utf8mb4"
        db, err = sqlx.Connect("mysql", dsn)
        if err != nil {
            fmt.Printf("Connect err : %v\n", err)
            return
        }
        db.SetMaxOpenConns(20)
        db.SetMaxIdleConns(10)
    
        //插入資料
        insertInfo()
    }
    

gin + mysql + rest full api

當然 之前說到的 http 包裡面的方法實現,我們也不需要用它了,我們們也可以交給框架,真的是可以做到高效實現業務,但同時,自己下來還是要去對具體的實現原理多研究研究

實踐如下步驟:

  • 匯入 github.com/gin-gonic/gin
  • 建立 users 表, id,name,telephone欄位

    CREATE TABLE `users` (
    `id` BIGINT(20) NOT NULL AUTO_INCREMENT,
    `name` VARCHAR(20) DEFAULT '',
    `telephone` VARCHAR(20) DEFAULT  '',
    PRIMARY KEY(`id`)
    )ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT 
    CHARSET=utf8mb4;

    <img src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/d8827a4583814e2cb9567af33ddbd3eb~tplv-k3u1fbpfcp-zoom-1.image" style="zoom:100%;"/>

上圖是實踐過程中產生的資料

  • 包裝對資料庫的增刪改查操作
  • 寫路由的操作

需要原始碼進行參考對比的 xdm ,可以評論或者私信,感謝能有反饋

歡迎點贊,關注,收藏

朋友們,你的支援和鼓勵,是我堅持分享,提高質量的動力

好了,本次就到這裡

技術是開放的,我們的心態,更應是開放的。擁抱變化,向陽而生,努力向前行。

我是小魔童哪吒,歡迎點贊關注收藏,下次見~

相關文章