Go 学习笔记(55)— Go 标准库 sql (初始化数据库、插入、更新、删除数据库表、单行查询、多行查询、事务处理)
1. 標準庫說明
Go 的標準庫中是沒有數據庫驅動,只提供了驅動接口,有很多第三方實現了驅動,我們這里選擇 go-sql-driver 這個實現是目前使用最多的。github 地址是:https://github.com/go-sql-driver/mysql
Go 標準庫中的 SQL 安裝包是在 $GOROOT/src/database/sql/ 目錄下,如下圖所示:
ubuntu@ubuntu:~$ ls /usr/local/go/src/database/sql/
convert.go doc.txt example_service_test.go sql.go
convert_test.go driver example_test.go sql_test.go
ctxutil.go example_cli_test.go fakedb_test.go
ubuntu@ubuntu:~$
2. 創建數據庫
在進行數據庫操作之前,我們先定義數據庫表結構:
CREATE TABLE IF NOT EXISTS test_user (`id` INT(3) NOT NULL AUTO_INCREMENT,`name` varchar(20) NOT NULL DEFAULT '',`age` smallint(3) unsigned NOT NULL DEFAULT '0',`gender` tinyint(1) unsigned NOT NULL DEFAULT '0',PRIMARY KEY (`id`)
)
ENGINE=InnoDB
DEFAULT CHARACTER SET = utf8;
3. 初始化數據庫
- 導入
go自帶的標準庫database/sql; - 命令行安裝三方庫
go get github.com/go-sql-driver/mysql; - 導入步驟 2 安裝的
mysql; - 打開數據庫格式是
?戶名:密碼@/數據庫名稱?編碼?式(包含了數據庫的用戶名、密碼、數據庫主機,以及需要連接的數據庫名等信息); - 最后關閉數據庫;
Go MySQL 驅動是 Go 標準庫 database/sql/driver 驅動程序接口的實現,我們只需要導入驅動程序就可以完整地使用 database/sql 的 API 。
使用 mysql 作為驅動名稱,有效的 DSN 作為數據源名稱, 使用示例:
import "database/sql"
import _ "github.com/go-sql-driver/mysql"DSN := "user:password@/dbname"
db, err := sql.Open("mysql", DSN)
其中數據源名稱 DSN 通用格式如下:
[username[:password]@][protocol[(address)]]/dbname[?param1=value1&...¶mN=valueN]
完整的格式為:
username:password@protocol(address)/dbname?param=value
除了 dbname 之外,其余所有值都是可選的,所以最小的 DSN 為:
/dbname
當然如果不選擇一個 DSN ,那么可以設置 dbname 為空,不過這樣沒有意義。
完整代碼示例如下:
package mainimport ("database/sql""fmt"_ "github.com/go-sql-driver/mysql"
)var DB *sql.DBfunc initDB() error {var err error// 打開數據庫格式dsn := "root:1234567@tcp(127.0.0.1:3306)/test?charset=utf8mb4"DB, err = sql.Open("mysql", dsn)if err != nil {return err}// defer DB.Close()return err}func main() {err := initDB()fmt.Println(err)
}
其中:
sql.Open不會立即建立網絡連接,只有下一次操作時才會進行連接;sql.Open返回的sql.DB對象是協程并發安全的,不需要我們自己去加解鎖;sql.DB可作為長連接使用,不需要頻繁Open、Close操作;
4. 更新刪除
sql.DB.Exec()方法,可以對數據庫進行新增、更新、刪除操作,只是SQL語句不同而已;- 返回的
Result類型主要有,影響的行數RowsAffected和最后插入的LastInsertId自增ID;
// sql.DB.Exec() 方法,可以對數據庫進行新增、更新、刪除操作,只是 SQL 語句不同而已
func insertUpdateDelete() {insertSQL := "INSERT INTO `test_user`(`name`,`age`) VALUES(?,?)"// query 語句中的 value 值在 DB.Exec 中來填充result, err := DB.Exec(insertSQL, "王五", 25)if err != nil {fmt.Printf("insert failed, err: %v\n", err)return}// 最新的自增 IDid, err := result.LastInsertId()if err != nil {fmt.Printf("LastInsertId failed, err: %v\n", err)return}// 獲取執行(影響)的行數//result.RowsAffected()fmt.Printf("last id=%d\n", id)
}
5. 單行查詢
- 使用
sql.DB.QueryRow()方法來執行查詢語句; - 使用
sql.Row.Scan()方法來獲取查詢結果;
我們定義一個 User 的結構體來存放數據。
// 用于存放用戶數據
type User struct {Id int `db:"id"`Name string `db:"name"`Age int `db:"age"`
}func queryResult() {querySQL := "SELECT `id`,`name`,`age` FROM `test_user` WHERE `id`=?"// 執行查詢語句row := DB.QueryRow(querySQL, 1)// 定義 user 為結構體 User 類型var user User// 此處獲取結果的順序一定要和 SELECT 語句取出的順序一樣err := row.Scan(&user.Id, &user.Name, &user.Age)if err != nil {fmt.Printf("query result failed, err: %v\n", err)return}fmt.Printf("query result: id=%d name=%s age=%d\n", user.Id, user.Name, user.Age)
}
需要說明的是,單行查詢時下面查詢的參數必須為 1,否則查詢的多余結果將被丟棄。
row := DB.QueryRow(querySQL, 1)
6. 多行查詢
多行查詢相對單行查詢來講要復雜一些。
sql.DB.Query()用來執行要查詢多行的SQL語句;sql.Rows.Next()用來迭代查詢下一個數據;sql.Rows.Scan()用來讀取每一行的值;sql.Rows.Close()關閉查詢;
func selectMultiRow(id int) {querySQL := "SELECT `id`,`name`,`age` FROM `test_user` WHERE `id`<?"// 執行多行查詢,注意此處用到的是 Query,單行查詢時用到的是 QueryRowrows, err := DB.Query(querySQL, id)if err != nil {fmt.Printf("querySQL failed, err: %v\n", err)return}defer rows.Close()var users = make([]User, 0, 5) // 創建一個容量為 5 個結構體類型的切片for rows.Next() {var user User// 獲取的順序一定要和 SELECT 語句取出的順序一樣err := rows.Scan(&user.Id, &user.Name, &user.Age)if err != nil {fmt.Printf("Next Scan failed, err: %v\n", err)return}users = append(users, user) // 將查詢到的結果添加到切片元素中去}fmt.Printf("selectMultiRow: %v\n", users)
}
7. 事務處理
Begin開始事務;Commit()提交事務;Rollback()回退事務;
我們這例子就是修改兩條數據:
func Trans(){// 開啟事務conn, err := DB.Begin()if err != nil {if conn != nil {// 出錯回滾 事務conn.Rollback()}fmt.Printf("begin faile, err: %v\n", err)return}query := "UPDATE `user` SET `age`=`age`+1 WHERE `id`=?"_, err = conn.Exec(query, 1)if err != nil {conn.Rollback()fmt.Printf("exec sql: %s failed, err: %v\n", query, err)return}query = "UPDATE `user` SET `name`='-name-' WHERE `id`=?"_, err = conn.Exec(query, 2)if err != nil {conn.Rollback()fmt.Printf("exec sql: %s failed, err: %v\n", query, err)return}// 提交事務err = conn.Commit()if err != nil {conn.Rollback()fmt.Printf("Commit failed, err: %v\n", err)return}fmt.Println("Commit ok")
}
參考:
https://gitbook.cn/books/5e7637996ba17a6d2c9a3352/index.html
https://github.com/go-sql-driver/mysql
總結
以上是生活随笔為你收集整理的Go 学习笔记(55)— Go 标准库 sql (初始化数据库、插入、更新、删除数据库表、单行查询、多行查询、事务处理)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2022-2028年中国塑料安瓿瓶行业市
- 下一篇: Go 学习笔记(56)— Go 第三方库