和上一節(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
建表 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, ®istTime, &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)
}
}