5.1 go-sql-driver/mysql
Go使用SQL与类SQL数据库的惯例是通过标准库database/sql。这是一个对关系型数据库的通用抽象,它提供了标准的、轻量的、面向行的接口。Go本身不提供具体数据库驱动,只提供驱动接口和管理,要使用数据库,除了database/sql
包本身,还需要引入想使用的特定数据库驱动。
现推荐一个我在项目中用到的驱动:
https://github.com/go-sql-driver/mysql
特征
- 轻巧快速
- Native Go实现。没有C-bindings,只是纯粹的Go
- 通过TCP / IPv4,TCP / IPv6,Unix域套接字或自定义协议进行连接
- 自动处理断开的连接
- 自动连接池(通过database / sql包)
- 支持大于16MB的查询
- 全力
sql.RawBytes
支持。 LONG DATA
准备好的报表中的智能处理LOAD DATA LOCAL INFILE
通过文件白名单和io.Reader
支持提供安全支持- 可选的
time.Time
解析 - 可选的占位符插值
要求
- 去1.8或更高。我们的目标是支持Go的3个最新版本。
- MySQL(4.1 +),MariaDB,Percona Server,Google CloudSQL或Sphinx(2.2.3+)
安装
使用shell中的go工具将包简单地安装到$ GOPATH:
$ go get -u github.com/go-sql-driver/mysql
确保Git已安装在您的计算机和系统中PATH
。
用法
使用sql.Open方法会创建一个数据库连接池db。这个db不是数据库连接,它是一个连接池,只有当真正数据库通信的时候才创建连接。例如这里的db.Ping
的操作。db.SetMaxIdleConns(20)
和db.SetMaxOpenConns(20)
分别设置数据库的空闲连接和最大打开连接,即向Mysql服务端发出的所有连接的最大数目。
注意:sql.DB
对象是为了长连接而设计的,不要频繁Open()
和Close()
数据库。而应该为每个待访问的数据库创建一个sql.DB
示例,并在用完前一直保留它。需要时可将其作为参数传递,或注册为全局对象。
如果没有按照database/sql
设计的意图,不把sql.DB
当成长期对象来用而频繁开关启停,就可能遭遇各式各样的错误:无法复用和共享连接,耗尽网络资源,由于TCP连接保持在TIME_WAIT
状态而间断性的失败等
示例:
package main
import (
"database/sql"
_ "github.com/go-sql-driver/mysql"
"log"
)
func main() {
db, err := sql.Open("mysql", "root:123456@tcp(127.0.0.1:3306)/testdb?charset=utf8mb4&parseTime=true")
defer db.Close()
if err != nil {
log.Fatalln(err)
}
//用于设置闲置的连接数。如果 <= 0, 则没有空闲连接会被保留
db.SetMaxIdleConns(0)
//用于设置最大打开的连接数,默认值为0表示不限制。
db.SetMaxOpenConns(30)
if err := db.Ping(); err != nil {
log.Fatalln(err)
}
}
测试表
CREATE TABLE `user` (
`id` int(10) NOT NULL COMMENT '主键',
`name` varchar(100) NOT NULL DEFAULT '' COMMENT '名字',
`ctime` int(11) NOT NULL DEFAULT '0' COMMENT '创建时间'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
示例:
package main
import (
"database/sql"
"fmt"
_ "github.com/go-sql-driver/mysql"
"log"
"time"
)
var db *sql.DB
func main() {
var err error
db, err = sql.Open("mysql", "root:123456@tcp(127.0.0.1:3306)/testdb?charset=utf8mb4&parseTime=true&&loc=Local")
//parseTime是查询结果是否自动解析为时间。
//loc是MySQL的时区设置。
defer db.Close()
if err != nil {
log.Fatalln(err)
}
//用于设置闲置的连接数。如果 <= 0, 则没有空闲连接会被保留
db.SetMaxIdleConns(0)
//用于设置最大打开的连接数,默认值为0表示不限制。
db.SetMaxOpenConns(30)
if err := db.Ping(); err != nil {
log.Fatalln(err)
}
//插入
insert()
//更新
update()
//查询
query()
//删除
delete()
}
func insert() {
tx, err := db.Begin()
if err != nil {
return
}
ctime := time.Now().Unix()
defer tx.Rollback()
stmt, err := tx.Prepare("INSERT INTO user (name,ctime) VALUES (?,?)")
if err != nil {
return
}
rs, err := stmt.Exec("李四", ctime)
if err != nil {
return
}
err = tx.Commit()
if err != nil {
return
}
id, err := rs.LastInsertId()
fmt.Println(id)
defer stmt.Close() //runs here!
return
}
func update() {
tx, err := db.Begin()
if err != nil {
return
}
defer tx.Rollback()
stmt, err := tx.Prepare("UPDATE user SET name=? WHERE id=?")
if err != nil {
return
}
_, err = stmt.Exec("zhangsan", 1)
if err != nil {
return
}
err = tx.Commit()
if err != nil {
return
}
defer stmt.Close()
return
}
func query() {
rows, err := db.Query("SELECT id,name,ctime FROM user ")
defer rows.Close()
if err != nil {
return
}
for rows.Next() {
var id, ctime int64
var name string
rows.Scan(&id, &name, &ctime)
fmt.Println(id, name, ctime)
}
if err = rows.Err(); err != nil {
return
}
return
}
func delete() {
tx, err := db.Begin()
if err != nil {
return
}
defer tx.Rollback()
stmt, err := tx.Prepare("DELETE FROM user WHERE id=?")
if err != nil {
return
}
_, err = stmt.Exec(1)
if err != nil {
return
}
err = tx.Commit()
if err != nil {
return
}
defer stmt.Close()
return
}