48. 訪問MySql數(shù)據(jù)庫增刪改查和連接池及空字段處理

和上一節(jié)相比,go 語言訪問 MySql 數(shù)據(jù)庫可以有更好的寫法,今天來講一下連接池。同時(shí),也演示一下當(dāng)表字段內(nèi)容為 NULL 時(shí),go 語言的處理。
首先我們建立一個(gè)新的數(shù)據(jù)庫 cofoxdb 和數(shù)據(jù)表 user

新增管理員
切換tab
設(shè)置用戶權(quán)限
新建數(shù)據(jù)庫 cofoxdb
雙擊數(shù)據(jù)庫成為當(dāng)前庫,點(diǎn)擊圖標(biāo)后寫入 SQL 建表腳本

建表 SQL 腳本

drop TABLE if exists `user`;
CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '流水號(hào)',
  `userName` varchar(45) NOT NULL COMMENT '用戶名【不可更改】',
  `password` varchar(255) NOT NULL COMMENT '密碼',
  `nickName` varchar(45) NOT NULL COMMENT '昵稱',
  `registTime` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '用戶注冊時(shí)間',
  `lastTimeLogin` datetime DEFAULT NULL COMMENT '上次登錄時(shí)間',
  `newLoginTime` datetime DEFAULT NULL COMMENT '最新登錄時(shí)間(當(dāng)前登錄時(shí)間)',
  `bak` varchar(1000) DEFAULT NULL COMMENT '備注',
  `online` char(1) DEFAULT 'N' COMMENT '當(dāng)前在線,Y/N\nY:在線\nN:不在線',
  `createTime` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '記錄創(chuàng)建時(shí)間',
  `creator` varchar(45) DEFAULT NULL COMMENT '記錄創(chuàng)建人',
  `updateTime` datetime DEFAULT NULL COMMENT '記錄修改時(shí)間',
  `updator` varchar(45) DEFAULT NULL COMMENT '記錄修改人',
  PRIMARY KEY (`id`,`userName`,`nickName`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COMMENT='All Registered users';

由于在一個(gè)應(yīng)用中會(huì)有多處代碼需要鏈接數(shù)據(jù)庫,所以我們準(zhǔn)備一個(gè)全局變量,供所有需要者調(diào)用。同時(shí)聲明的也有 error 變量。

var db *sql.DB
var err error

需要給 db 實(shí)例化,建立一個(gè) init() 函數(shù),這樣,在 main() 函數(shù)執(zhí)行前就可以把數(shù)據(jù)庫鏈接完成初始化了。

func init()  {
    db, err = sql.Open("mysql", "cofox:Q1w2e3r4@tcp(127.0.0.1:3306)/cofoxdb?charset=utf8")
    check(err)

    db.SetMaxOpenConns(2000)
    db.SetMaxIdleConns(1000)
    check(db.Ping())
}

db.SetMaxOpenConns(2000) 是設(shè)置這個(gè)連接池最大鏈接數(shù)是 2000 個(gè)。
db.SetMaxIdleConns(1000) 設(shè)置的是連接池內(nèi)最低保持 1000 個(gè)待用鏈接。這樣當(dāng)有需要訪問的程序請求時(shí),就可以從連接池內(nèi)分配一條已有的鏈接。提高訪問效率。
db.Ping() 是為了讓程序和數(shù)據(jù)庫進(jìn)行真正的鏈接(sql.Open并沒有建立真正的連接關(guān)系,只是初始化。)

插入數(shù)據(jù)

直接使用 db.Prepare ,因?yàn)?db 已經(jīng)初始化了。
res.LastInsertId() 執(zhí)行后返回最新的 id。如果是批量數(shù)據(jù)插入的話,這個(gè)會(huì)返回第一條記錄的 id。

func insert()  {
    stmt, err := db.Prepare(`INSERT user (userName, password, nickName) VALUES (?, ?, ?)`)
    check(err)

    res, err := stmt.Exec("cofox_1","123456","冷靜的狐貍")
    check(err)

    id, err := res.LastInsertId()
    check(err)

    fmt.Println(id)
    stmt.Close()

}
修改數(shù)據(jù)

也是直接使用 db
res.RowsAffected() 提交執(zhí)行,返回修改了的記錄數(shù)。

func update() {
    stmt, err := db.Prepare("UPDATE user set nickName=?, updateTime=?, updator=?, bak=? WHERE id=?")
    check(err)

    res, err := stmt.Exec("厚土火焰山",time.Now().Format("2006-01-02 15:04:05"),"root","測試更新\r\ngo直連數(shù)據(jù)庫", 1)
    check(err)

    num, err := res.RowsAffected()
    check(err)

    fmt.Println(num)
    stmt.Close()
}
刪除數(shù)據(jù)

同上
res.RowsAffected()提交執(zhí)行,返回刪除了的記錄數(shù)。

func remove() {
    stmt, err := db.Prepare("DELETE FROM cofoxdb WHERE id=?")
    check(err)

    res, err := stmt.Exec(7)
    check(err)

    num, err := res.RowsAffected()
    check(err)

    fmt.Println(num)
    stmt.Close()

}
查詢數(shù)據(jù)

因?yàn)楸碜侄屋^多,很多字段在新增后或許仍然沒有寫入相應(yīng)的數(shù)據(jù),這些字段如果沒有默認(rèn)值的話,就會(huì)是 NULL 值。
NULL 值在 go 語言中是不能寫入 string time.Time 的。所以這里我們使用 "database/sql" 提供的 sql.NullString 類型。當(dāng)然 Null** 類型還有很多 NullInt64、NullFloat64、NullBool

        var id int
        var userName string
        var password string
        var nickName string
        var registTime string
        var lastTimeLogin sql.NullString
        var newLoginTime sql.NullString
        var bak sql.NullString
        var online sql.NullString
        var createTime sql.NullString
        var creator sql.NullString
        var updateTime sql.NullString
        var updator sql.NullString

我們用這個(gè)類型來處理字段有可能為 NULL 的數(shù)據(jù)。這樣就可以正常讀取記錄值了。
這些 NullString 的類型結(jié)構(gòu)是這樣的

type NullString struct {
    String string
    Valid  bool // Valid is true if String is not NULL
}

都是有兩個(gè)字段在里面。而 String 字段就是我們最終想要的東西。所以,在輸出或使用的時(shí)候,我們這樣組織代碼

lastTimeLogin.String, newLoginTime.String, bak.String, online.String, createTime.String, creator.String, updateTime.String, updator.String

執(zhí)行 insert() 后,我們再執(zhí)行 query2(),得到如下結(jié)果

id = "3", userName = "cofox_1", password = "123456", nickName = "冷靜的狐貍", registTime = "2017-09-07 17:39:02", lastTimeLogin = "", newLoginTime = "", bak = "", online = "N", createTime = "2017-09-07 17:39:02", creator = "", updateTime = "", updator = ""

看完整代碼示例

package main

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

var db *sql.DB
var err error

func init()  {
    db, err = sql.Open("mysql", "cofox:Q1w2e3r4@tcp(127.0.0.1:3306)/cofoxdb?charset=utf8")
    check(err)

    db.SetMaxOpenConns(2000)
    db.SetMaxIdleConns(1000)
    check(db.Ping())
}

func main() {
    //query()
    query2()
    //insert()
    //update()
    //remove()
}



//查詢數(shù)據(jù)
func query() {
    rows, err := db.Query("SELECT * FROM user")
    check(err)

    for rows.Next() {
        columns, _ := rows.Columns()

        scanArgs := make([]interface{}, len(columns))
        values := make([]interface{}, len(columns))

        for i := range values {
            scanArgs[i] = &values[i]
        }

        //將數(shù)據(jù)保存到 record 字典
        err = rows.Scan(scanArgs...)
        record := make(map[string]string)
        for i, col := range values {
            if col != nil {
                record[columns[i]] = string(col.([]byte))
            }
        }
        fmt.Println(record)
    }
    rows.Close()

}
func query2()  {
    rows, err := db.Query("SELECT id, userName, password, nickName, registTime, lastTimeLogin, newLoginTime, bak, online, createTime, creator, updateTime, updator FROM user")
    check(err)

    for rows.Next(){
        var id int
        var userName string
        var password string
        var nickName string
        var registTime string
        var lastTimeLogin sql.NullString
        var newLoginTime sql.NullString
        var bak sql.NullString
        var online sql.NullString
        var createTime sql.NullString
        var creator sql.NullString
        var updateTime sql.NullString
        var updator sql.NullString

        //注意這里的Scan括號(hào)中的參數(shù)順序,和 SELECT 的字段順序要保持一致。
        if err := rows.Scan(&id, &userName, &password, &nickName, &registTime, &lastTimeLogin, &newLoginTime, &bak, &online, &createTime, &creator, &updateTime, &updator); err != nil {
            log.Fatal(err)
        }

        fmt.Printf("id = \"%d\", userName = \"%s\", password = \"%s\", nickName = \"%s\", registTime = \"%s\", lastTimeLogin = \"%s\", newLoginTime = \"%s\", bak = \"%s\", online = \"%s\", createTime = \"%s\", creator = \"%s\", updateTime = \"%s\", updator = \"%s\"\n",id, userName, password, nickName, registTime, lastTimeLogin.String, newLoginTime.String, bak.String, online.String, createTime.String, creator.String, updateTime.String, updator.String)

    }

    if err := rows.Err(); err != nil {
        log.Fatal(err)
    }
    rows.Close()
}

//插入數(shù)據(jù)
func insert()  {
    stmt, err := db.Prepare(`INSERT user (userName, password, nickName) VALUES (?, ?, ?)`)
    check(err)

    res, err := stmt.Exec("cofox_1","123456","冷靜的狐貍")
    check(err)

    id, err := res.LastInsertId()
    check(err)

    fmt.Println(id)
    stmt.Close()

}

//修改數(shù)據(jù)
func update() {
    stmt, err := db.Prepare("UPDATE user set nickName=?, updateTime=?, updator=?, bak=? WHERE id=?")
    check(err)

    res, err := stmt.Exec("厚土火焰山",time.Now().Format("2006-01-02 15:04:05"),"root","測試更新\r\ngo直連數(shù)據(jù)庫", 1)
    check(err)

    num, err := res.RowsAffected()
    check(err)

    fmt.Println(num)
    stmt.Close()
}

//刪除數(shù)據(jù)
func remove() {
    stmt, err := db.Prepare("DELETE FROM cofoxdb WHERE id=?")
    check(err)

    res, err := stmt.Exec(7)
    check(err)

    num, err := res.RowsAffected()
    check(err)

    fmt.Println(num)
    stmt.Close()

}

func check(err error) {
    if err != nil{
        fmt.Println(err)
        panic(err)
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容