Go語言操作MySQL語言基礎知識
前言
通常情況下,我們程序員和數據庫打交道是最多的。要然我們怎么會被稱為碼農呢。
存用戶信息需要數據庫,存訂單需要數據庫,等等等等,現(xiàn)在真是數據驅動著發(fā)展。
但是數據庫種類有很多,有Mysql,Oracle,SQL Server。
本篇就示例如何Go操作Mysql。
準備工作
本次使用的是go mod進行包依賴管理,還不會使用的向上爬梯子,找go mod用法。
使用的庫是第三方庫go-sql-driver/mysql。
準備工作之連接數據庫
代碼
func main() {
var username = "root"
var password = "rootroot"
var ip = "127.0.0.1"
var port = "3306"
var data = "go_mysql_demo"
var dsn = fmt.Sprintf("%s:%s@tcp(%s:%s)/%s", username, password, ip, port, data)
//Open只會驗證dsb的格式是否正確,不會驗證是否連接成功,同理,密碼是否正確也不知道
db, err := sql.Open("mysql", dsn)
if err != nil {
panic(err)
}
//關閉連接在 err 之后,因為可能直接就打開不成功,關閉一個沒有打開的連接???
defer db.Close()
// 此時嘗試連接數據庫,會判斷用戶,密碼,ip地址,端口是否正確
err = db.Ping()
if err != nil {
fmt.Println("連接數據庫失敗,",err)
return
}
//設置與數據庫建立連接的最大數目,一般不管
db.SetMaxOpenConns(100)
//設置連接池中的最大閑置連接數,一般不管
db.SetMaxIdleConns(50)
}
注意
- sql.Open只會驗證格式是否正確,不會連接數據庫。
- db.Close在err之后,是因為可能打開不成功,關閉一個沒有打開的連接。
- db.Ping會連接數據庫,判斷用戶,密碼,ip地址,端口是否正確。
準備工作之創(chuàng)建表
我們創(chuàng)建一個簡單的用戶表。
CREATE TABLE `userinfo` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(10) DEFAULT NULL,
`phone` char(11) DEFAULT NULL,
`address` varchar(64) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
準備工作之創(chuàng)建結構體
假設上述工作都完成了啊。
不知道有沒有想過,我們查詢的數據,存成啥?,字符串?map?切片?,似乎都不是太好。
只有結構體是最清晰的,最好認識的。
結構體
type Userinfo struct {
Id int64 `json:"id"`
Name string `json:"name"`
Phone string `json:"phone"`
Address string `json:"address"`
}
查詢單條
單條查詢使用QueryRow方法。
代碼
//查詢單條
sqlStr := "SELECT id,`name`,phone,address from userinfo where id = ?;"
var user Userinfo
/*
QueryRow 第二個參數可以接收多個參數,同理,sqlStr可以有多個 ?占位符 進行匹配
QueryRow 之后必須調用Scan方法進行數據綁定,進行數據庫鏈接釋放
*/
err = db.QueryRow(sqlStr, 1).Scan(&user.Id, &user.Name, &user.Phone, &user.Address)
if err != nil {
fmt.Println("查詢失敗", err)
return
}
fmt.Println(user)
執(zhí)行結果
查詢多條
多行查詢使用Query。
代碼
//查詢多條
sqlStr := "SELECT id,`name`,phone,address from userinfo where id >= ?"
//參數同 QueryRow
rows, err := db.Query(sqlStr, 1)
if err != nil {
fmt.Println("查詢失敗:", err)
return
}
// 此處使用rows釋放所有鏈接
defer rows.Close()
//循環(huán)整理所有數據
var userList = make([]Userinfo, 0, 10)
for rows.Next() {
var user Userinfo
err = rows.Scan(&user.Id, &user.Name, &user.Phone, &user.Address)
if err != nil {
fmt.Println("綁定數據失敗", err)
return
}
userList = append(userList, user)
}
fmt.Println(userList)
執(zhí)行結果
插入數據
插入數據需要用到Exec。
代碼
//插入數據
sqlStr := "INSERT into userinfo(name,phone,address) values(?,?,?);"
result, err := db.Exec(sqlStr, "吳彥祖", 555, "不知道哪的")
if err != nil {
fmt.Println("插入失敗", err)
return
}
//受影響的行數
row_affect, err := result.RowsAffected()
if err != nil {
fmt.Println("受影響行數獲取失敗:", err)
return
}
fmt.Println("受影響的行數:", row_affect)
lastId, err := result.LastInsertId()
if err != nil {
fmt.Println("新增行id獲取失敗:", err)
return
}
fmt.Println("新增行id:", lastId)
fmt.Println("插入成功")
執(zhí)行結果
Mysql
更新數據
更新和添加差不多,用的都是Exec。
代碼
//更新數據
sqlStr := `UPDATE userinfo set name=? where id=?;`
result, err := db.Exec(sqlStr, "吳彥祖666", 3)
if err != nil {
fmt.Println("更新失敗", err)
return
}
//受影響的行數
row_affect, err := result.RowsAffected()
if err != nil {
fmt.Println("受影響行數獲取失敗:", err)
return
}
fmt.Println("受影響的行數:", row_affect)
fmt.Println("更新成功")
執(zhí)行結果
Mysql
刪除數據
刪除數據用的還是Exec。
代碼
//刪除數據
sqlStr := "delete from userinfo where id = ?;"
result, err := db.Exec(sqlStr, 3)
if err != nil {
fmt.Println("刪除失敗", err)
return
}
//受影響的行數
row_affect, err := result.RowsAffected()
if err != nil {
fmt.Println("受影響行數獲取失敗:", err)
return
}
fmt.Println("受影響的行數:", row_affect)
fmt.Println("刪除成功")
執(zhí)行結果
Mysql
事物
事物,這個用的就比較多了,通常用在關鍵的場景。
尤其是轉賬,張三-10塊,李四+10塊,這個動作動作是要在一起完成的。
如果任何一個失敗了,就要恢復上一次的狀態(tài)。
我們通常也叫這個操作叫做原子操作,要成功,都成功,要完蛋,都完蛋。
新建表
CREATE TABLE `bill` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(8) NOT NULL,
`money` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4;
表數據
張三和李四都剩余100塊
Go Mysql 關于事物相關方法
Go 關于事物有三個方法
- Begin()開始事物。
- Commit()提交事物。
- Rollback()失敗回滾。
模擬轉賬:張三-10塊,李四+十塊
代碼
func main() {
//事物
//開啟事物
tx, err := db.Begin()
if err != nil {
//釋放事物
if tx != nil {
tx.Rollback()
}
fmt.Println("事物開啟失敗")
return
}
張三減10塊Sql := `UPDATE bill set mnotallow=money - 10 where name = ?;`
result, err := tx.Exec(張三減10塊Sql, "張三")
if err != nil {
//有錯誤表示更是失敗,回滾原來狀態(tài)
tx.Rollback()
fmt.Println(err)
return
}
張三受影響行數, err := result.RowsAffected()
if err != nil {
tx.Rollback() // 回滾
return
}
李四加10塊Sql := `UPDATE bill set mnotallow=money + 10 where name = ?;`
result, err = tx.Exec(李四加10塊Sql, "李四")
if err != nil {
//有錯誤表示更是失敗,回滾原來狀態(tài)
tx.Rollback()
fmt.Println(err)
return
}
李四受影響行數, err := result.RowsAffected()
if err != nil {
tx.Rollback() // 回滾
return
}
//都等于1表示成功,可以提交事務,修改數據
if 張三受影響行數==1 && 李四受影響行數==1{
//提交事務
fmt.Println("提交事務")
tx.Commit()
}else{
//有一個!=1表示沒有更新成功,可能用戶不存在
fmt.Println("失敗了,事物回滾了")
tx.Rollback()
}
fmt.Println("事物執(zhí)行成功")
}
執(zhí)行結果
Mysql
一加一減
假如出錯了
Mysql
如果使用事物,出錯了數據還是沒變。
總結
本次主要講述了Go如何操作Mysql,如何進行增刪改查,最后還講了以下什么是事物,如何操作事物。
當然,這種是最原始的方法,過程有些繁瑣,了解入門就好,后面還有更方便的方法。