这是我参与「第五届青训营 」伴学笔记创作活动的第 11 天
本文介绍如何使用Go来连接MySQL数据库
MySQL的具体使用,例如建库建表和SQL语法就不赘述了
Go中使用MySQL
下载需要的包
$ go get github.com/go-sql-driver/mysql
$ go get github.com/jmoiron/sqlx
前一个是MySQL的驱动,后一个是基于MySQL驱动的封装
连接MySQL数据库的操作
database, err := sqlx.Open("mysql","root:XXX@tcp(127.0.1:3306)/test")
//database, err := sqlx.Open("数据库类型", "用户名:密码@tcp(地址:端口)/数据库名")
Insert
首先导包,导入MySQL驱动
package main
import (
"fmt"
_ "github.com/go-sql-driver/mysql"
"github.com/jmoiron/sqlx"
)
定义数据结构体
type Person struct {
UserId int `db:"user_id"`
Username string `db:"username"`
Sex string `db:"sex"`
Email string `db:"email"`
}
在init()函数中连接数据库,需要将*sqlx.DB作为全局变量使用
var Db *sqlx.DB
func init() {
database, err := sqlx.Open("mysql", "root:root@tcp(127.0.0.1:3306)/test")
if err != nil {
fmt.Println("open mysql failed,", err)
return
}
Db = database
defer Db.Close() // 注意这行代码要写在上面err判断的下面
// 代表延迟关闭数据库(退出init()时关闭数据库,防止资源泄露)
}
实现简单的插入操作
func main() {
r, err := Db.Exec("INSERT INTO person(username, sex, email)VALUES(?, ?, ?)", "stu001", "man", "stu01@qq.com")
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)
}
或者使用Db.Prepare() + stmt.Exec()函数
stmt, err := Db.Prepare("INSERT ....")
if err != nil {
// 错误处理
}
res, err := stmt.Exec("astaxie", "研发部门", "2012-12-09")
if err != nil {
// 错误处理
}
Db.Prepare () 函数用来返回准备要执行的 sql 操作,然后返回准备完毕的执行状态。
stmt.Exec () 函数用来执行 stmt 准备好的 SQL 语句
我们传入的参数都是 =? 对应的数据,这样做的方式可以一定程度上防止 SQL 注入。
Select
导包、init()函数、结构体定义与Insert中相同
查询单行数据
使用Db.Get()函数,接口如下
func (db *DB) Get(dest interface{}, query string, args ...interface{}) error
dest接收查询结果,query是查询语句,args为参数赋值
func main() {
var person Person
err := Db.Get(&person,"SELECT user_id, username FROM person WHERE user_id = ?", 1)
if err != nil {
fmt.Println("exec failed, ", err)
return
}
fmt.Println("select succ:", person)
}
查询多行数据
使用Db.Select()函数,接口如下
func (db *DB) Select(dest interface{}, query string, args ...interface{}) error
func main() {
var person []Person
err := Db.Select(&person, "SELECT user_id, username, sex, email FROM person WHERE user_id > ?", 0)
if err != nil {
fmt.Println("exec failed, ", err)
return
}
fmt.Println("select succ:", person)
}
Update
func main() {
res, err := Db.Exec("UPDATE person SET username=? WHERE user_id=?", "stu0003", 1)
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)
}
Delete
func main() {
res, err := Db.Exec("DELETE FROM person WHERE user_id=?", 1)
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)
}
不使用sqlx包
sqlx是 Go 的软件包,它在内置database/sql包的基础上提供了一组扩展。
该库兼容sql原生包,同时又提供了更为强大的、优雅的查询、插入函数。前文的示例使用了sqlx包的处理函数
如果不使用sqlx包,则使用func sql.Open(driverName, dataSourceName string) (*DB, error)打开数据库(打开一个注册过的数据库驱动),第二个参数dataSourceName支持很多格式,如下
例如
Db, err := sql.Open("mysql", "root:XXX@tcp(localhost:3306)/test")
通常情况 Open 函数只需调用一次,并很少需要关闭。若需要显式关闭,使用函数 func (db *DB) Close() error 完成,前文的代码中init()函数中的``
插入、更新、删除操作sqlx和原生sql一样,参考前文代码即可
查询操作有不一样的地方
Select
查询多行
rows, err := Db.Query("SELECT * FROM person")
查询单行
var username string
err := Db.QueryRow("SELECT ... WHERE id=?", 100).Scan(&username)
函数 func (db *DB) QueryRow(query string, args ...interface{}) *Row 执行查询操作,返回一行 sql.Row 类对象,参数 query 为查询 SQL。args 为 query 中占位参数
得到的 sql.Row 对象为单行结果集,需要使用 func (r *Row) Scan(dest ...interface{}) error 函数获取结果集中某个字段数据。如果该查询匹配多行,Scan 会使用第一行结果并丢弃其余各行,如果没有匹配查询的行,Scan 会返回 ErrNoRows。
参考资料
go操作MySQL · Go语言中文文档 (topgoer.com)