Go語言中mysql資料庫操作(一)

airland發表於2021-09-09


資料的持久化是程式中必不可少的,所以程式語言中對資料庫的操作是非常重要的一塊,本文介紹Go語言對mysql資料庫的操作。

基本操作

建立連線

db, err := sql.Open("mysql", "root:root@tcp(127.0.0.1:3306)/betting?charset=utf8")

errDeal("連線資料庫", err)

defer db.Close()

連線引數一般有以下幾種

user@unix(/path/to/socket)/dbname?charset=utf8

user:password@tcp(localhost:5555)/dbname?charset=utf8

user:password@/dbname

user:password@tcp([de:ad:be:ef::ca:fe]:80)/dbname

增刪改操作

// 插入資料---------------------方法1

result, err := db.Exec("INSERT INTO admin_log(admin_username,log_time,log_ip,log_type,log_desc)" +

" VALUES(?,now(),?,?,?)", "admin", "127.0.0.1", "登入", "登入成功")

errDeal("插入資料", err)

// 檢視返回資訊

count, err := result.RowsAffected()

errDeal("檢視插入資料條數", err)

fmt.Printf("插入資料條數:%dn", count)

id, err := result.LastInsertId()

errDeal("檢視最後插入資料的id", err)

fmt.Printf("最後插入資料的id:%dn", id)

// 插入資料---------------------方法2,先建立一個預處理語句,再執行

stmt, err := db.Prepare("INSERT INTO admin_log(admin_username,log_time,log_ip,log_type,log_desc)" +

" VALUES(?,now(),?,?,?)")

result1, err1 := stmt.Exec("admin", "127.0.0.1", "登入", "登入成功")

errDeal("方法2插入資料", err1)

fmt.Println(result1.LastInsertId())

// 刪除資料

result2, err := db.Exec("DELETE FROM admin_log WHERE id=?", 2014)

fmt.Println(result2.RowsAffected())

// 更新資料

result3, err := db.Exec("UPDATE admin_log SET log_ip=? WHERE id=?", "192.168.8.9", 2017)

fmt.Println(result3.RowsAffected())

單條資料查詢

// 先定義儲存查詢結果的變數

var rid int

var username, time, ip, logType string

var desc, remark, spare interface{} // 如果欄位中可能出現值為nil的情況,可以將變數申明為interface{}型別

err2 := db.QueryRow("SELECT id,admin_username,log_time,log_ip,log_type,log_desc,remark,spare" +

    " FROM admin_log WHERE id=?", 2017).Scan(&rid, &username, &time, &ip, &logType, &desc, &remark, &spare) // 傳入的是變數的指標

errDeal("查詢單條資料", err2)

fmt.Printf("id=%d,username=%s,time=%s,ip=%s,logType=%s,desc=%s,remark=%v,spare=%vn", rid, username, time, ip, logType, desc, remark, spare)

多條資料查詢

// 查詢多條資料

rows, err3 := db.Query("SELECT admin_username,log_time,log_ip,log_type,log_desc" +

    " FROM admin_log WHERE id=? OR id=?", 2017, 2019)

errDeal("查詢多條資料", err3)

// 對多條資料進行遍歷

for rows.Next() {

    err4 := rows.Scan(&username, &time, &ip, &logType, &desc)

    errDeal("遍歷多條資料", err4)

    fmt.Printf("username=%s,time=%s,ip=%s,logType=%s,desc=%sn", username, time, ip, logType, desc)

}

// 如果查詢中不指定具體欄位,使用*

rows, err33 := db.Query("SELECT *" +

    " FROM admin_log WHERE id>?", 2017)

errDeal("查詢多條資料", err33)

// 查詢所有欄位名,返回string切片

columes, err333 := rows.Columns()

errDeal("rows.Columns()方法呼叫", err333)

fmt.Printf("%T----%vn", columes, columes)

var scanColumes = make([]interface{}, len(columes))

var values = make([]interface{}, len(columes))

for index, _ := range  scanColumes {

    scanColumes[index] = &values[index]

}

for rows.Next() {

    err4 := rows.Scan(scanColumes...)

    errDeal("遍歷多條資料", err4)

    for i, val := range values {

        if strings.EqualFold(judgeType(val), "[]uint8") {

            fmt.Printf("%s(%T)==%st", columes[i], val, val)

        } else {

            fmt.Printf("%s(%T)==%vt", columes[i], val, val)

        }

    }

    fmt.Println()

}

事務

開啟事務

// 開啟事務,tx是從連線池中取出一個連線,在關閉之前都是使用這個連線,提交事務和回滾事務都是操作tx

tx, err5 := db.Begin()

errDeal("開啟事務", err5)

_, err6 := tx.Exec("UPDATE admin_log SET log_desc=? WHERE id=?", "測試事務222", 2019)

//if err6 != nil {

if err6 == nil {

    tx.Rollback() // 回滾

}

tx.Commit() // 提交

批次插入資料

// 批次資料插入

tx, err7 := db.Begin()

errDeal("資料批次插入,開啟事務", err7)

insertValues := [][]interface{}{{"admin", "127.0.0.1", "登入", "登入成功"},{"admin", "127.0.0.1", "刪除", "刪除資料"},{"admin", "127.0.0.1", "退出", "退出系統"}}

stmt, err8 := tx.Prepare("INSERT INTO admin_log(admin_username,log_time,log_ip,log_type,log_desc) VALUES(?,now(),?,?,?)")

errDeal("資料批次插入,預處理", err8)

for _, val := range  insertValues {

    _, err := stmt.Exec(val...)

    if err != nil {

        fmt.Printf("出現錯誤回滾,錯誤資訊:%v", err)

        tx.Rollback()

    }

}

tx.Commit()

sqlx的使用及批次插入

xdb, err9 := sqlx.Open("mysql", "root:root@tcp(127.0.0.1:3306)/betting?charset=utf8")

errDeal("sqlx連線資料庫", err9)

txx, err10 := xdb.Beginx()

errDeal("sqlx開啟事務", err10)

insertValuesx := [][]interface{}{{"admin", "127.0.0.1", "登入", "登入成功X"},{"admin", "127.0.0.1", "刪除", "刪除資料X"},{"admin", "127.0.0.1", "退出", "退出系統X"}}

stmtx, err11 := txx.Preparex("INSERT INTO admin_log(admin_username,log_time,log_ip,log_type,log_desc) VALUES(?,now(),?,?,?)")

errDeal("資料批次插入,預處理", err11)

for _, val := range insertValuesx {

    _, err := stmtx.Exec(val...)

    if err != nil {

        fmt.Printf("sqlx出現錯誤回滾,錯誤資訊:%v", err)

        txx.Rollback()

    }

}

txx.Commit()

完整程式碼

package main

import (

    "database/sql"

    _"github.com/go-sql-driver/mysql" // 這裡很重要,匯入自己本地使用的資料庫驅動,前面是下劃線,否則會報錯:sql: unknown driver "mysql" (forgotten import?)

    "fmt"

    "strings"

    "github.com/jmoiron/sqlx"

)

func main() {

    // 連線資料庫,使用者名稱:密碼@協議(地址:埠)/資料庫?引數=引數值,常用"使用者名稱:密碼@tcp(ip:埠)/資料庫名?charset=字符集"

    db, err := sql.Open("mysql", "root:root@tcp(127.0.0.1:3306)/betting?charset=utf8")

    errDeal("連線資料庫", err)

    defer db.Close()

    //=========================================================================================增刪改

    // 插入資料---------------------方法1

    result, err := db.Exec("INSERT INTO admin_log(admin_username,log_time,log_ip,log_type,log_desc)" +

        " VALUES(?,now(),?,?,?)", "admin", "127.0.0.1", "登入", "登入成功")

    errDeal("插入資料", err)

    // 檢視返回資訊

    count, err := result.RowsAffected()

    errDeal("檢視插入資料條數", err)

    fmt.Printf("插入資料條數:%dn", count)

    id, err := result.LastInsertId()

    errDeal("檢視最後插入資料的id", err)

    fmt.Printf("最後插入資料的id:%dn", id)

    // 插入資料---------------------方法2,先建立一個預處理語句,再執行

    stmt, err := db.Prepare("INSERT INTO admin_log(admin_username,log_time,log_ip,log_type,log_desc)" +

        " VALUES(?,now(),?,?,?)")

    result1, err1 := stmt.Exec("admin", "127.0.0.1", "登入", "登入成功")

    errDeal("方法2插入資料", err1)

    fmt.Println(result1.LastInsertId())

    // 刪除資料

    result2, err := db.Exec("DELETE FROM admin_log WHERE id=?", 2014)

    fmt.Println(result2.RowsAffected())

    // 更新資料

    result3, err := db.Exec("UPDATE admin_log SET log_ip=? WHERE id=?", "192.168.8.9", 2017)

    fmt.Println(result3.RowsAffected())

    //=============================================================================================查詢

    // 查詢單條資料

    // 先定義儲存查詢結果的變數

    var rid int

    var username, time, ip, logType string

    var desc, remark, spare interface{} // 如果欄位中可能出現值為nil的情況,可以將變數申明為interface{}型別

    err2 := db.QueryRow("SELECT id,admin_username,log_time,log_ip,log_type,log_desc,remark,spare" +

        " FROM admin_log WHERE id=?", 2017).Scan(&rid, &username, &time, &ip, &logType, &desc, &remark, &spare) // 傳入的是變數的指標

    errDeal("查詢單條資料", err2)

    fmt.Printf("id=%d,username=%s,time=%s,ip=%s,logType=%s,desc=%s,remark=%v,spare=%vn", rid, username, time, ip, logType, desc, remark, spare)

    // 查詢多條資料

    rows, err3 := db.Query("SELECT admin_username,log_time,log_ip,log_type,log_desc" +

        " FROM admin_log WHERE id=? OR id=?", 2017, 2019)

    errDeal("查詢多條資料", err3)

    // 對多條資料進行遍歷

    for rows.Next() {

        err4 := rows.Scan(&username, &time, &ip, &logType, &desc)

        errDeal("遍歷多條資料", err4)

        fmt.Printf("username=%s,time=%s,ip=%s,logType=%s,desc=%sn", username, time, ip, logType, desc)

    }

    // 如果查詢中不指定具體欄位,使用*

    rows, err33 := db.Query("SELECT *" +

        " FROM admin_log WHERE id>?", 2017)

    errDeal("查詢多條資料", err33)

    // 查詢所有欄位名,返回string切片

    columes, err333 := rows.Columns()

    errDeal("rows.Columns()方法呼叫", err333)

    fmt.Printf("%T----%vn", columes, columes)

    var scanColumes = make([]interface{}, len(columes))

    var values = make([]interface{}, len(columes))

    for index, _ := range  scanColumes {

        scanColumes[index] = &values[index]

    }

    for rows.Next() {

        err4 := rows.Scan(scanColumes...)

        errDeal("遍歷多條資料", err4)

        for i, val := range values {

            if strings.EqualFold(checkType(val), "[]uint8") {

                fmt.Printf("%s(%T)==%st", columes[i], val, val)

            } else {

                fmt.Printf("%s(%T)==%vt", columes[i], val, val)

            }

        }

        fmt.Println()

    }

    // ==================================================================================================事務

    // 開啟事務,tx是從連線池中取出一個連線,在關閉之前都是使用這個連線,提交事務和回滾事務都是操作tx

    tx, err5 := db.Begin()

    errDeal("開啟事務", err5)

    _, err6 := tx.Exec("UPDATE admin_log SET log_desc=? WHERE id=?", "測試事務222", 2019)

    //if err6 != nil {

    if err6 == nil {

        tx.Rollback() // 回滾

    }

    tx.Commit() // 提交

    // 批次資料插入

    tx, err7 := db.Begin()

    errDeal("資料批次插入,開啟事務", err7)

    insertValues := [][]interface{}{{"admin", "127.0.0.1", "登入", "登入成功"},{"admin", "127.0.0.1", "刪除", "刪除資料"},{"admin", "127.0.0.1", "退出", "退出系統"}}

    stmt, err8 := tx.Prepare("INSERT INTO admin_log(admin_username,log_time,log_ip,log_type,log_desc) VALUES(?,now(),?,?,?)")

    errDeal("資料批次插入,預處理", err8)

    defer stmt.Close()

    // 透過迴圈將每條SQL的引數寫到目標表緩衝區。

    for _, val := range  insertValues {

        _, err := stmt.Exec(val...)

        if err != nil {

            fmt.Printf("出現錯誤回滾,錯誤資訊:%v", err)

            tx.Rollback()

        }

    }

    tx.Commit()

    // 使用sqlx批次資料插入

    xdb, err9 := sqlx.Open("mysql", "root:root@tcp(127.0.0.1:3306)/betting?charset=utf8")

    errDeal("sqlx連線資料庫", err9)

    defer xdb.close()

    txx, err10 := xdb.Beginx()

    errDeal("sqlx開啟事務", err10)

    insertValuesx := [][]interface{}{{"admin", "127.0.0.1", "登入", "登入成功X"},{"admin", "127.0.0.1", "刪除", "刪除資料X"},{"admin", "127.0.0.1", "退出", "退出系統X"}}

    stmtx, err11 := txx.Preparex("INSERT INTO admin_log(admin_username,log_time,log_ip,log_type,log_desc) VALUES(?,now(),?,?,?)")

    errDeal("資料批次插入,預處理", err11)

    defer stmtx.Close()

    // 透過迴圈將每條SQL的引數寫到目標表緩衝區。

    for _, val := range insertValuesx {

        _, err := stmtx.Exec(val...)

        if err != nil {

            fmt.Printf("sqlx出現錯誤回滾,錯誤資訊:%v", err)

            txx.Rollback()

        }

    }

    txx.Commit()

}

func errDeal(info string, err error) {

    if err != nil {

        panic(fmt.Sprintf("%s,錯誤資訊:%v", info, err))

    }

}

func checkType(val interface{}) string {

    switch val.(type) {

    case []uint8 :

        return "[]uint8"

    }

    return ""

}

©著作權歸作者所有:來自51CTO部落格作者thao888的原創作品,如需轉載,請註明出處,否則將追究法律責任


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/964/viewspace-2819604/,如需轉載,請註明出處,否則將追究法律責任。

相關文章