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

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

新增管理員
切換tab
設(shè)置用戶權(quán)限
新建數(shù)據(jù)庫(kù) cofoxdb
雙擊數(shù)據(jù)庫(kù)成為當(dāng)前庫(kù),點(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 '用戶注冊(cè)時(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ù)庫(kù)谨娜,所以我們準(zhǔn)備一個(gè)全局變量,供所有需要者調(diào)用磺陡。同時(shí)聲明的也有 error 變量趴梢。

var db *sql.DB
var err error

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

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)有需要訪問(wèn)的程序請(qǐng)求時(shí),就可以從連接池內(nèi)分配一條已有的鏈接拍冠。提高訪問(wèn)效率尿这。
db.Ping() 是為了讓程序和數(shù)據(jù)庫(kù)進(jìn)行真正的鏈接(sql.Open并沒(méi)有建立真正的連接關(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","測(cè)試更新\r\ngo直連數(shù)據(jù)庫(kù)", 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)楸碜侄屋^多栖博,很多字段在新增后或許仍然沒(méi)有寫入相應(yīng)的數(shù)據(jù),這些字段如果沒(méi)有默認(rèn)值的話厢洞,就會(huì)是 NULL 值仇让。
NULL 值在 go 語(yǔ)言中是不能寫入 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è)類型來(lái)處理字段有可能為 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() 后,我們?cè)賵?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","測(cè)試更新\r\ngo直連數(shù)據(jù)庫(kù)", 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)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末溉躲,一起剝皮案震驚了整個(gè)濱河市虚吟,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌签财,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,826評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件偏塞,死亡現(xiàn)場(chǎng)離奇詭異唱蒸,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)灸叼,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門神汹,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人古今,你說(shuō)我怎么就攤上這事屁魏。” “怎么了捉腥?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,234評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵氓拼,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我抵碟,道長(zhǎng)桃漾,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,562評(píng)論 1 293
  • 正文 為了忘掉前任拟逮,我火速辦了婚禮撬统,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘敦迄。我一直安慰自己恋追,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,611評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布罚屋。 她就那樣靜靜地躺著苦囱,像睡著了一般。 火紅的嫁衣襯著肌膚如雪沿后。 梳的紋絲不亂的頭發(fā)上沿彭,一...
    開(kāi)封第一講書(shū)人閱讀 51,482評(píng)論 1 302
  • 那天,我揣著相機(jī)與錄音尖滚,去河邊找鬼喉刘。 笑死瞧柔,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的睦裳。 我是一名探鬼主播造锅,決...
    沈念sama閱讀 40,271評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼廉邑!你這毒婦竟也來(lái)了哥蔚?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,166評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤蛛蒙,失蹤者是張志新(化名)和其女友劉穎糙箍,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體牵祟,經(jīng)...
    沈念sama閱讀 45,608評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡深夯,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,814評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了诺苹。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片咕晋。...
    茶點(diǎn)故事閱讀 39,926評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖收奔,靈堂內(nèi)的尸體忽然破棺而出掌呜,到底是詐尸還是另有隱情,我是刑警寧澤坪哄,帶...
    沈念sama閱讀 35,644評(píng)論 5 346
  • 正文 年R本政府宣布质蕉,位于F島的核電站,受9級(jí)特大地震影響翩肌,放射性物質(zhì)發(fā)生泄漏饰剥。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,249評(píng)論 3 329
  • 文/蒙蒙 一摧阅、第九天 我趴在偏房一處隱蔽的房頂上張望汰蓉。 院中可真熱鬧,春花似錦棒卷、人聲如沸顾孽。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,866評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)若厚。三九已至,卻和暖如春蜒什,著一層夾襖步出監(jiān)牢的瞬間测秸,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,991評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留霎冯,地道東北人铃拇。 一個(gè)月前我還...
    沈念sama閱讀 48,063評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像沈撞,于是被迫代替她去往敵國(guó)和親慷荔。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,871評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容