目录
一、驱动介绍
目前Go语言中支持MySQL的驱动较多,部分是支持database/sql标准,部分是采用自己实现的接口。
常用的驱动有如下几种:
- GitHub - go-sql-driver/mysql: Go MySQL Driver is a MySQL driver for Go's (golang) database/sql package
https://github.com/go-sql-driver/mysql支持database/sql,全部采用Go语言编写。
- GitHub - ziutek/mymysql: MySQL Client API written entirely in GoMySQL Client API written entirely in Go. Contribute to ziutek/mymysql development by creating an account on GitHub.
https://github.com/ziutek/mymysql支持database/sql,也支持自定义的接口,全部采用Go语言编写。
- GitHub - Philio/GoMySQL: The most complete and stable MySQL client library written completely in Go. For discussion, ideas, suggestions, feature requests etc, please visit the GoMySQL Google Group (link below). For any issues/bugs or need some help, please post an issue on Github.The most complete and stable MySQL client library written completely in Go. For discussion, ideas, suggestions, feature requests etc, please visit the GoMySQL Google Group (link below). For any issues/bugs or need some help, please post an issue on Github. - GitHub - Philio/GoMySQL: The most complete and stable MySQL client library written completely in Go. For discussion, ideas, suggestions, feature requests etc, please visit the GoMySQL Google Group (link below). For any issues/bugs or need some help, please post an issue on Github.
https://github.com/Philio/GoMySQL不支持database/sql,自定义接口,全部采用Go语言编写。
二、go-sql-driver/mysql 介绍与应用
2.1 采用理由
- 该驱动比较新,维护得比较好。
- 完全支持database/sql接口。
- 支持Keepalive,保持长链接。
2.2 实践与应用
这里采用go_test数据库、user表。
建表语句
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键自增',
`user_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '用户名',
`depart_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
`create_at` date NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
增删改查
package main
import (
"database/sql"
"fmt"
_ "github.com/go-sql-driver/mysql"
)
type User struct {
id int64
username string
departName string
createAt string
}
func main() {
db, err := sql.Open("mysql", "root:123456@tcp(192.168.158.328:33066)/go_test?charset=utf8")
checkErr(err)
// 插入数据
userId := insertUserOne(db)
// 查询数据
queryUserOne(db)
// 更改数据
updateUserOne(db, userId)
// 查询数据
queryUserOne(db)
// 删除数据
deleteUserOne(db, userId)
}
// 插入用户数据
func insertUserOne(db *sql.DB) (userId int64) {
stmt, err := db.Prepare("INSERT user set user_name=?,depart_name=?,create_at=?")
checkErr(err)
res, err := stmt.Exec("李四", "运营部", "2000-10-10")
checkErr(err)
// 得到插入后的主键id
id, err := res.LastInsertId()
checkErr(err)
fmt.Println("插入后返回主键id", id)
return id
}
// 更新用户数据
func updateUserOne(db *sql.DB, id int64) {
stmt, err := db.Prepare("update user set user_name= ? where id=?")
checkErr(err)
res, err := stmt.Exec("李四改", id)
checkErr(err)
affected, err := res.RowsAffected()
checkErr(err)
fmt.Println("作用的更新记录数", affected)
}
// 查询用户,暂时就不返回list了
func queryUserOne(db *sql.DB) {
// 这里查询出来的字段顺序需要与结构体字段顺序吧保持一致
rows, err := db.Query("SELECT * FROM user")
checkErr(err)
for rows.Next() {
user := User{}
err := rows.Scan(&user.id, &user.username, &user.departName, &user.createAt)
checkErr(err)
fmt.Println("查询到的用户数据", user.id, user.username, user.departName, user.createAt)
}
}
// 删除用户数据
func deleteUserOne(db *sql.DB, id int64) {
stmt, err := db.Prepare("delete from user where id=?")
checkErr(err)
res, err := stmt.Exec(id)
checkErr(err)
affected, err := res.RowsAffected()
checkErr(err)
fmt.Println("删除作用行数", affected)
db.Close()
}
// 检查错误
func checkErr(err error) {
if err != nil {
panic(err)
}
}
运行结果
插入后返回主键id 4
查询到的用户数据 4 李四 运营部 2000-10-10
作用的更新记录数 1
查询到的用户数据 4 李四改 运营部 2000-10-10
删除作用行数 1
三、补充说明
3.1 sql.Open函数
该函数旨在打开一个注册过的数据库驱动,需要引入 _ "github.com/go-sql-driver/mysql" ,不然程序会报错。
该函数第一个参数是数据库驱动名称,这里是 mysql。
该函数第二个参数是Data Source Name,及链接和配置信息,支持格式如:
- user@unix(/path/to/socket)/dbname?charset=utf8
- username:password@tcp(localhost:3306)/dbname?charset=utf8 (本文采用)
- username:password@/dbname
- username:password@tcp([de:ad:be:ee::ca:fe]:80)/dbname
源代码如下:
func Open(driverName, dataSourceName string) (*DB, error) {
driversMu.RLock()
driveri, ok := drivers[driverName]
driversMu.RUnlock()
if !ok {
return nil, fmt.Errorf("sql: unknown driver %q (forgotten import?)", driverName)
}
if driverCtx, ok := driveri.(driver.DriverContext); ok {
connector, err := driverCtx.OpenConnector(dataSourceName)
if err != nil {
return nil, err
}
return OpenDB(connector), nil
}
return OpenDB(dsnConnector{dsn: dataSourceName, driver: driveri}), nil
}
3.2 db.Prepare()函数
用来返回准备要执行的SQL操作,然后返回准备完毕的执行状态。源代码如下:
func (db *DB) Prepare(query string) (*Stmt, error) {
return db.PrepareContext(context.Background(), query)
}
3.3 db.Query()函数
用来直接执行SQL返回Rows结果,源代码如下:
func (db *DB) Query(query string, args ...interface{}) (*Rows, error) {
return db.QueryContext(context.Background(), query, args...)
}
3.4 stmt.Exec()
用来执行stmt准备好的语句,源代码如下:
// Exec executes a prepared statement with the given arguments and
// returns a Result summarizing the effect of the statement.
//
// Exec uses context.Background internally; to specify the context, use
// ExecContext.
func (s *Stmt) Exec(args ...interface{}) (Result, error) {
return s.ExecContext(context.Background(), args...)
}
PS:
不用数据库链接后考虑关掉数据库链接。