[Go][Mysql] 使用Go进行mysql数据库CRUD

454 阅读4分钟

一、简介

Go中支持的MySQL驱动比较多,推荐最多的是github.com/go-sql-driv…,支持database/sql标准。

二、使用前的准备

1.引用

需要引用两个包

import "database/sql"
import _ "github.com/go-sql-driver/mysql"

备注:_ 是只引入包名(即只使用init函数注册mysql数据库驱动)而不直接使用包重定义的函数

引入后可能会报如下的错:

解决方案:从 github.com/go-sql-driv… 中将压缩包下载,然后解压到目录($GOROOT\src\github.com\go-sql-driver\mysql\)中,如下图所示:

2.连接数据库

sql.Open() 打开一个由其数据库驱动程序名称和驱动程序特定的数据源名称指定的数据库,通常由至少一个数据库名称和连接信息组成。方法定义如下:

func Open(driverName, dataSourceName string) (*DB, error)

有两个参数:第一个参数driverName是注册进去的数据库名称,第二个参数是数据库连接和配置信息。格式如下:
user@unix(/path/to/socket)/dbname?charset=utf8
user:password@tcp(localhost:3306)/dbname?charset=utf8(推荐)
user:password@/dbname
user:password@tcp([de:ad:be:ef::ca:fe]:80)/dbname

db,err := sql.Open("mysql", "root:@tcp(localhost:3306)/default?charset=utf8")
if err != nil {
    panic(err)
}

三、mysql基本操作(增删改查)

db.Prepare()方法为以后的查询或执行创建一个准备好的语句(用于增删改),返回一个准备完毕的执行状态stmt

func (db *DB) Prepare(query string) (*Stmt, error)

stmt.Exec()使用给定的参数执行一个准备好的语句,并返回一个总结语句效果的Result结果集

func (s *Stmt) Exec(args ...interface{}) (Result, error)

1.增改查(操作都差不多,故放一块)

db,err := sql.Open("mysql", "root:root@tcp(localhost:3306)/default?charset=utf8")
if err != nil {
    panic(err)
}
//新增一条数据
stmt, err := db.Prepare(`INSERT user (uname, age, mobile) VALUES (?, ?, ?)`)
if err != nil {
    panic(err)
}
defer stmt.Close() //延时关闭一个准备好的资源
res, err := stmt.Exec("fightWang",28,"18888888888")
if err != nil {
    panic(err)
}
//更新数据(修改id=5的数据)
stmt, err = db.Prepare("update user set mobile=? where id=?")
if err != nil {
    panic(err)
}
res, err = stmt.Exec("18899999999",5) 
//删除数据(删除id=5的数据)
stmt, err = db.Prepare("DELETE FROM user where id=?")
if err != nil {
    panic(err)
}
res, err = stmt.Exec(5) 

增删改也可以直接使用db.Exec()方法(注意与stmt.Exec()的区别)

func (db *DB) Exec(query string, args ...interface{}) (Result, error)

2.查(多条)

与增删改一样,可以配合db.Prepare()使用stmt.Query()方法来查询,结果返回Rows结果集

func (s *Stmt) Query(args ...interface{}) (*Rows, error)

stmt, err := db.Prepare(`SELECT * FROM user WHERE mobile=?`)
if err != nil {
    panic(err)
}
rows, err := stmt.Query("18888888888")
if err != nil {
    panic(err)
}

查询操作也可以直接使用db.Query()方法(注意与stmt.Query()的区别)

func (db *DB) Query(query string, args ...interface{}) (*Rows, error)

rows返回结果是多个结果行的集合,可以通过rows.Next()和rows.Scan()方法来获取行内数据
rows.Next()接下来准备下一个结果行以便用Scan方法读取。它在成功时返回true,如果没有下一个结果行或在准备过程中发生错误,则返回false。
func (rs *Rows) Next() bool
rows.Close() 关闭行,防止进一步枚举。如果Next被调用并返回false,并且没有其他结果集,则行自动关闭,并且检查Err的结果就足够了。关闭是幂等的,不会影响Err的结果。故在调用的时候使用defer rows.Close()是一个好习惯
func (rs *Rows) Close() error
rows.Scan()将当前行中的列复制到dest指向的值中。dest中的值数量必须与行中的列数相同

func (rs *Rows) Scan(dest ...interface{}) error

rows, err := db.Query("SELECT * FROM user") //user表中共四个字段
if err != nil {
    panic(err)
}
defer rows.Close()
uid, uname, age, mobile := 0,"",0,""
for rows.Next() {
    err = rows.Scan(&uid,&uname,&age,&mobile) //要四个字段一一对齐
    if err != nil {
        panic(err)
    }
    fmt.Println(uid, uname, age, mobile)
}

3.查询(单条查询)

可以通过db.QueryRow()或者配合db.Prepare()和stmt.QueryRow()查询单条结果。
db.QueryRow()执行一个查询,该查询最多只返回一行。QueryRow总是返回一个非零值。错误被推迟到行的扫描方法被调用(row.Scan())。
func (db *DB) QueryRow(query string, args ...interface{}) *Row
stmt.QueryRow()使用给定的参数执行一个准备好的查询语句。如果在执行语句期间发生错误,则在返回的*行上调用Scan以返回该错误,该行总是非零

func (s *Stmt) QueryRow(args ...interface{}) *Row

id := 123
var username string
err := db.QueryRow("SELECT username FROM users WHERE id=?", id).Scan(&username)
switch {
case err == sql.ErrNoRows: //当QueryRow没有返回行时,Scan返回ErrNoRows。在这种情况下,QueryRow会返回一个占位符* Row值,该值将推迟发生此错误直到扫描。
        log.Printf("No user with that ID.")
case err != nil:
        log.Fatal(err)
default:
        fmt.Printf("Username is %s\n", username)
}

四、mysql其他常用操作

1.获取执行插入行操作的主键id值

LastInsertId() (int64, error)

//新增一条数据
stmt, err := db.Prepare(`INSERT user (uname, age, mobile) VALUES (?, ?, ?)`)
if err != nil {
    panic(err)
}
res, err := stmt.Exec("fightWang",28,"18888888888")
if err != nil {
    panic(err)
}
uid, err := res.LastInsertId()
if err != nil {
    panic(err)
}
fmt.Println(uid) //返回新插入行的主键

2.返回受到影响的行数(Insert | Update | Delete)

num, err := res.RowsAffected()
if err != nil {
    panic(err)
}
fmt.Println(num) //返回新插入行的主键

3.获取表的字段(列)名(仅用于多条查询)

rows.Columns() 将返回列名称组成的slice。如果行关闭,或者行来自QueryRow并且存在延迟错误,则列将返回错误。

func (rs *Rows) Columns() ([]string, error)

stmt, err := db.Prepare("SELECT * FROM user")
if err != nil {
    panic(err)
}
defer stmt.Close()
rows, err := stmt.Query()
if err != nil {
    panic(err)
}
defer rows.Close()
columns, err := rows.Columns()
if err != nil {
    panic(err)
}
fmt.Println(columns) //[id uname age mobile]