Golang學習筆記之Golang與Mysql交互

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())
    }
}
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容