Go標準庫中沒有數據庫驅動。參見http://golang.org/s/sqldrivers獲取第三方驅動。
這里選擇了Go-MySQL-Driver這個實現。地址是:https://github.com/go-sql-driver/mysql/。
安裝:go get github.com/go-sql-driver/mysql
官方database/sql包文檔:https://studygolang.com/pkgdoc
有關于MySQL基本操作可以去看我的另一篇簡書:http://www.lxweimin.com/p/2e01f4c6b626
使用的數據庫定義如下
一、打開數據庫
函數原型
func Open(driverName, dataSourceName string) (*DB, error)
Open打開一個dirverName指定的數據庫,dataSourceName指定數據源,一般包至少括數據庫文件名和(可能的)連接信息。
//第?步:打開數據庫,格式是 ?戶名:密碼@/數據庫名稱?編碼?式
db, err := sql.Open("mysql", "root:123@/mydb?charset=utf8")
if err != nil {
fmt.Println(err)
}
//關閉數據庫
defer db.Close()
二、查詢數據
函數原型
func (db *DB) Query(query string, args ...interface{}) (*Rows, error)
Query執行一次查詢,返回多行結果(即Rows),一般用于執行select命令。參數args表示query中的占位參數。
var id int
var name string
var price float64
//查詢數據,指定字段名,返回sql.Rows結果集
rows, err := db.Query("select id,name,price from product")
if err != nil {
fmt.Println(err)
}
for rows.Next() {
rows.Scan(&id, &name, &price)
fmt.Println(id, name, price)
}
defer rows.Close()
? rows.Next() 迭代查詢數據.
? rows.Scan() 讀取每一行的值
? rows.Close() 關閉查詢
三、查詢一行數據
函數原型
func (db *DB) QueryRow(query string, args ...interface{}) *Row
QueryRow執行一次查詢,并期望返回最多一行結果(即Row)。QueryRow總是返回非nil的值,直到返回值的Scan方法被調用時,才會返回被延遲的錯誤。
//查詢??數據可以使用and(與)限定多個條件,或者使用or(或)
rows3 := db.QueryRow("SELECT id,name FROM product WHERE id = ? or price like ?", 1,1.11)
// rows3 := db.QueryRow("select id,name from product where id = 1")
rows3.Scan(&id, &name)
fmt.Println(id, name)
四、插入一行數據
函數原型
func (s *Stmt) Exec(args ...interface{}) (Result, error)
Exec使用提供的參數執行準備好的命令狀態,返回Result類型的該狀態執行結果的總結。
//插???數據
ret, _ := db.Exec("insert into product(id,name,price) values(15,'dog',30)")
//LastInsertId返回一個數據庫生成的回應命令的整數。
//返回插入的ID
insID, _ := ret.LastInsertId()
fmt.Println(insID)
? ret.LastInsertId()插入的ID
? ret.RowsAffected()受影響的行數
五、修改數據
//更新數據,修改id>1的行的name
ret2, _ := db.Exec("update product set name= '000' where id > ?", 1)
//獲取影響?數
aff_nums, _ := ret2.RowsAffected()
fmt.Println(aff_nums)
六、刪除數據
//刪除數據,刪除id=3的行
ret3, _ := db.Exec("delete from product where id = ?",3)
delNums, _ := ret3.RowsAffected()
fmt.Println(delNums)
七、預處理
函數原型
func (db *DB) Prepare(query string) (*Stmt, error)
Prepare創建一個準備好的狀態用于之后的查詢和命令。返回值可以同時執行多個查詢和命令。
//預處理
stmt, _ := db.Prepare("select id,name from product where id=? or name=?")
//查找id為3或者name為000的人
row4, _ := stmt.Query(3, "000")
//注意這?需要Next()下,不然下?取不到值
for row4.Next() {
row4.Scan(&id, &name)
fmt.Println(id, name)
}
//預處理插入數據
stmt2, _ := db.Prepare("insert into product(name,id,price) values(?,?,null)")
//name為lisi,id為22
rows5, _ := stmt2.Exec("lisi", 22)
fmt.Println(rows5.RowsAffected())
八、事務處理
函數原型
func (db *DB) Begin() (*Tx, error)
Begin開始一個事務。隔離水平由數據庫驅動決定。
//開啟事務
tx, _ := db.Begin()
//id為1的price+1,id為2的price-1
ret4, _ := tx.Exec("update product set price = price + 1 where id = ?", 1)
ret5, _ := tx.Exec("update product set price = price - 1 where id = ?", 2)
//如果id不存在,受影響行數則為0
//接收影響行數,為0則失敗
updNums1, _ := ret4.RowsAffected()
updNums2, _ := ret5.RowsAffected()
if updNums1 > 0 && updNums2 > 0 { //只有兩條更新同時成功,那么才提交
tx.Commit() //提交事務
fmt.Println("Success")
} else { //否則回滾
tx.Rollback() //回退事務
fmt.Println("Fail")
}
? tx.Commit() 提交事務
? tx.Rollback() 回退事務
demo
package main
import (
"database/sql"
"fmt"
_ "github.com/go-sql-driver/mysql"
)
type dbWorker struct {
dsn string
db *sql.DB
userInfo usertb
}
type usertb struct {
id int
//NullString代表一個可為NULL的字符串。
name sql.NullString
//NullInt64代表一個可為NULL的Float64值。
price sql.NullFloat64
}
func main() {
var err error
//初始化結構體,保存數據庫參數
dbw := dbWorker{
dsn: "root:123@/mydb?charset=utf8",
}
//打開數據庫,并保存給結構體內db
dbw.db, err = sql.Open("mysql", dbw.dsn)
//如果打開失敗,panic退出
if err != nil {
panic(err)
}
//關閉數據庫
defer dbw.db.Close()
//插入數據
dbw.insertData()
//獲取數據
dbw.querData()
}
//創建方法,插入數據
func (dbw *dbWorker) insertData() {
//預處理,插入數據
stmt, _ := dbw.db.Prepare(`INSERT INTO product(name,id,price) VALUES(?,null,?)`)
//函數執行完畢,關閉
defer stmt.Close()
//插入數據
ret, err := stmt.Exec("hz", 29)
if err != nil {
fmt.Println(err)
return
}
//獲取id,執行成功,打印
if LastInsertId, err := ret.LastInsertId(); err == nil {
fmt.Println("LastInsertId:", LastInsertId)
}
//獲取行號,執行成功,打印
if RowsAffected, err := ret.RowsAffected(); err == nil {
fmt.Println("RowsAffected:", RowsAffected)
}
}
//初始化userInfo
func (dbw *dbWorker) querDataPre() {
dbw.userInfo = usertb{}
}
func (dbw *dbWorker) querData() {
//預處理,查詢數據
stmt, _ := dbw.db.Prepare(`SELECT * From product where price >= ? AND price < ?`)
defer stmt.Close()
dbw.querDataPre()
//取price20到30之間的數據
rows, err := stmt.Query(20, 30)
defer rows.Close()
if err != nil {
fmt.Println(err)
return
}
for rows.Next(){
//取出數據庫數據
rows.Scan(&dbw.userInfo.id,&dbw.userInfo.name,&dbw.userInfo.price)
if err != nil {
fmt.Println(err.Error())
continue
}
//如果取出的數據為null,則賦一個0值
if !dbw.userInfo.name.Valid{
dbw.userInfo.name.String = ""
}
if !dbw.userInfo.price.Valid{
dbw.userInfo.price.Float64 = 0.00
}
fmt.Println("get data,id:",dbw.userInfo.id,"name:",dbw.userInfo.name.String,"price",float64(dbw.userInfo.price.Float64))
}
err = rows.Err()
if err != nil{
fmt.Printf(err.Error())
}
}