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基本操作可以去看我的另一篇简书:https://www.jianshu.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())
    }
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335

推荐阅读更多精彩内容