Go語言操作MySQL數據庫
MySQL是一個關系型數據庫管理系統,由瑞典MySQL AB 公司開發,目前屬於 Oracle 旗下產品。MySQL 是最流行的關系型數據庫管理系統之一,在 WEB 應用方面,MySQL是最好的 RDBMS (Relational Database Management System,關系數據庫管理系統) 應用軟件。 Go語言MySQL包 使用第三方開源的mysql庫: github.com/go-sql-driver/mysql (MySQL驅動) github.com/jmoiron/sqlx (基於MySQL驅動的封裝) 通過如下命令,保存下載第三方庫: go get github.com/go-sql-driver/mysql go get github.com/jmoiron/sqlx 創建數據庫、數據表 在MySQL下創建 oldboy庫: mysql> CREATE DATABASE IF NOT EXISTS oldboy DEFAULT CHARSET utf8 COLLATE utf8_general_ci; 在oldboy庫中創建student表。 mysql> use oldboy; mysql> CREATE TABLE IF NOT EXISTS `student`( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `name` varchar(100) NOT NULL, `sex` varchar(40) NOT NULL, `age` int(11) DEFAULT NULL, `course` varchar(100) NOT NULL, PRIMARY KEY (`id`) )ENGINE=InnoDB DEFAULT CHARSET=utf8; MySQL連接池 數據庫連接使用datebase/sql Open函數進行連接,用戶應該通過db.Ping()函數來檢查數據庫是否實際可用。 package main import ( "fmt" _ "github.com/go-sql-driver/mysql" "github.com/jmoiron/sqlx" ) func main() { //DB, err := sqlx.Open("數據庫類型", "用戶名:密碼@tcp(地址:端口)/數據庫名") DB, err := sqlx.Open("mysql", "root:root@tcp(127.0.0.1:3306)/oldboy") if err != nil { fmt.Println("Open mysql failed,", err) } err = DB.Ping() if err != nil { fmt.Println("Ping mysql failed,", err) } else { fmt.Println("MySQL client success") } } 連接池配置 配置連接池有兩個的函數: 設置最大數據庫連接:使用 db.SetMaxOpenConns(n int) 函數設置打開數據庫的最大連接數。包含正在使用的連接和連接池的連接。如果你的函數調用需要申請一個連接,並且連接池已經沒有了連接或者連接數達到了最大連接數。此時的函數調用將會被block,直到有可用的連接才會返回。設置這個值可以避免並發太高導致連接mysql出現too many connections的錯誤。該函數的默認設置是0,表示無限制。 設置最大空閑連接:使用db.SetMaxIdleConns(n int) 函數設置連接池中的保持連接的最大連接數。默認也是0,表示連接池不會保持釋放會連接池中的連接的連接狀態:即當連接釋放回到連接池的時候,連接將會被關閉。這會導致連接再連接池中頻繁的關閉和創建。 插入操作 建議使用結構化操作,不推薦使用直接拼接sql語句的方法。 package main import ( "fmt" _ "github.com/go-sql-driver/mysql" "github.com/jmoiron/sqlx" ) type Student struct { Id int `db:"id"` Name string `db:"name"` Sex string `db:"sex"` Age int `db:"age"` Course string `db:"course"` } var Db *sqlx.DB func init() { database, err := sqlx.Open("mysql", "root:root@tcp(127.0.0.1:3306)/oldboy") if err != nil { fmt.Println("open mysql failed,", err) return } Db = database } func main() { r, err := Db.Exec("insert into student(name, sex, age, course)values(?, ?, ?, ?)", "張三", "男", 18, "Golang") if err != nil { fmt.Println("exec failed, ", err) return } id, err := r.LastInsertId() if err != nil { fmt.Println("exec failed, ", err) return } fmt.Println("insert succ:", id) } 查詢操作 package main import ( "fmt" _ "github.com/go-sql-driver/mysql" "github.com/jmoiron/sqlx" ) type Student struct { Id int `db:"id"` Name string `db:"name"` Sex string `db:"sex"` Age int `db:"age"` Course string `db:"course"` } var Db *sqlx.DB func init() { database, err := sqlx.Open("mysql", "root:root@tcp(127.0.0.1:3306)/oldboy") if err != nil { fmt.Println("open mysql failed,", err) return } Db = database } func main() { var student []Student err := Db.Select(&student, "select id, name, sex, age, course from student where course=?", "Golang") if err != nil { fmt.Println("exec failed, ", err) return } fmt.Println("select succ:", student) } 修改操作 package main import ( "fmt" _ "github.com/go-sql-driver/mysql" "github.com/jmoiron/sqlx" ) type Student struct { Id int `db:"id"` Name string `db:"name"` Sex string `db:"sex"` Age int `db:"age"` Course string `db:"course"` } var Db *sqlx.DB func init() { database, err := sqlx.Open("mysql", "root:root@tcp(127.0.0.1:3306)/oldboy") if err != nil { fmt.Println("open mysql failed,", err) return } Db = database } func main() { res, err := Db.Exec("update student set name=? where course=?", "李四", "Golang") if err != nil { fmt.Println("exec failed, ", err) return } row, err := res.RowsAffected() if err != nil { fmt.Println("rows failed, ", err) } fmt.Println("update succ:", row) } 刪除操作 package main import ( "fmt" _ "github.com/go-sql-driver/mysql" "github.com/jmoiron/sqlx" ) type Student struct { Id int `db:"id"` Name string `db:"name"` Sex string `db:"sex"` Age int `db:"age"` Course string `db:"course"` } var Db *sqlx.DB func init() { database, err := sqlx.Open("mysql", "root:root@tcp(127.0.0.1:3306)/oldboy") if err != nil { fmt.Println("open mysql failed,", err) return } Db = database } func main() { res, err := Db.Exec("delete from student where name=?", "李四") if err != nil { fmt.Println("exec failed, ", err) return } row, err := res.RowsAffected() if err != nil { fmt.Println("rows failed, ", err) } fmt.Println("delete succ: ", row) } 修改和刪除操作都比較簡單,同插入數據類似,只是使用RowsAffected來獲取影響的數據行數。 MySQL事務 MySQL 事務主要用於處理操作量大,復雜度高的數據。 在 MySQL 中只有使用了 Innodb 數據庫引擎的數據庫或表才支持事務。 事務處理可以用來維護數據庫的完整性,保證成批的 SQL 語句要么全部執行,要么全部不執行。 事務用來管理 insert,update,delete 語句 一般來說,事務是必須滿足4個條件(ACID):原子性(Atomicity,或稱不可分割性)、一致性(Consistency)、隔離性(Isolation,又稱獨立性)、持久性(Durability)。 Go語言MySQL事務應用包與函數: 1) import ("github.com/jmoiron/sqlx") 2) conn, err := Db.Begin() 開始事務 3) conn.Commit() 提交事務 4) conn.Rollback() 回滾事務 事務應用 package main import ( "fmt" _ "github.com/go-sql-driver/mysql" "github.com/jmoiron/sqlx" ) type Student struct { Id int `db:"id"` Name string `db:"name"` Sex string `db:"sex"` Age int `db:"age"` Course string `db:"course"` } var Db *sqlx.DB func init() { database, err := sqlx.Open("mysql", "root:root@tcp(127.0.0.1:3306)/oldboy") if err != nil { fmt.Println("open mysql failed,", err) return } Db = database } func main() { conn, err := Db.Begin() if err != nil { fmt.Println("begin failed :", err) return } r, err := Db.Exec("insert into student(name, sex, age, course)values(?, ?, ?, ?)", "王五", "男", 18, "Golang") if err != nil { fmt.Println("exec failed, ", err) conn.Rollback() return } id, err := r.LastInsertId() if err != nil { fmt.Println("exec failed, ", err) conn.Rollback() return } fmt.Println("insert succ:", id) r, err = Db.Exec("insert into student(name, sex, age, course)values(?, ?, ?, ?)", "趙六", "男", 18, "Linux、Python、Java") if err != nil { fmt.Println("exec failed, ", err) conn.Rollback() return } id, err = r.LastInsertId() if err != nil { fmt.Println("exec failed, ", err) conn.Rollback() return } fmt.Println("insert succ:", id) conn.Commit() } 查看MySQL: mysql> select id,name,sex,age,course from student; +----+--------+-----+------+-----------------------+ | id | name | sex | age | course | +----+--------+-----+------+-----------------------+ | 2 | 王五 | 男 | 18 | Golang | | 3 | 趙六 | 男 | 18 | Linux、Python、Java | +----+--------+-----+------+-----------------------+ 2 rows in set (0.00 sec) Go語言操作mysql除使用 github.com/go-sql-driver/mysql第三方開源的mysql庫外還可以使用github.com/jinzhu/gorm包,GORM是使用Go語言開發的友好的ORM庫。 安裝 go get -u github.com/jinzhu/gorm 通用數據庫接口sql.DB 從*gorm.DB連接獲取通用數據庫接口*sql.DB // 獲取通用數據庫對象`*sql.DB`以使用其函數 db.DB() // Ping db.DB().Ping() 連接池 db.DB().SetMaxIdleConns(10) db.DB().SetMaxOpenConns(100) 復合主鍵 將多個字段設置為主鍵以啟用復合主鍵 type Product struct { ID string `gorm:"primary_key"` LanguageCode string `gorm:"primary_key"` } 日志 Gorm有內置的日志記錄器支持,默認情況下,它會打印發生的錯誤 // 啟用Logger,顯示詳細日志 db.LogMode(true) // 禁用日志記錄器,不顯示任何日志 db.LogMode(false) // 調試單個操作,顯示此操作的詳細日志 db.Debug().Where("name = ?", "jinzhu").First(&User{}) 自定義日志 參考GORM的默認記錄器如何自定義 https://github.com/jinzhu/gorm/blob/master/logger.go db.SetLogger(gorm.Logger{revel.TRACE}) db.SetLogger(log.New(os.Stdout, "\r\n", 0)) 架構 Gorm使用可鏈接的API,*gorm.DB是鏈的橋梁,對於每個鏈API,它將創建一個新的關系。 db, err := gorm.Open("postgres", "user=gorm dbname=gorm sslmode=disable") // 創建新關系 db = db.Where("name = ?", "jinzhu") // 過濾更多 if SomeCondition { db = db.Where("age = ?", 20) } else { db = db.Where("age = ?", 30) } if YetAnotherCondition { db = db.Where("active = ?", 1) } 當我們開始執行任何操作時,GORM將基於當前的*gorm.DB創建一個新的*gorm.Scope實例 // 執行查詢操作 db.First(&user) 並且基於當前操作的類型,它將調用注冊的creating,updating,querying,deleting或row_querying回調來運行操作。
