sqlx
1. 准备工作
-- 用户表信息
create table if not exists test.`user`
(
`id` int not null auto_increment primary key,
`userid` int not null comment '用户id',
`username` varchar(256) not null comment '用户名',
`password` varchar(256) not null comment '用户密码',
`avatar` varchar(256) not null comment '用户头像',
`create_time` datetime default null comment '创建时间',
`update_time` datetime default null on update CURRENT_TIMESTAMP comment '更新时间'
) comment '用户表信息';
insert into test.`user` (`id`, `userid`, `username`, `password`, `avatar`) values (0, 702, '郑弘文', 'BY', 'www.johnetta-homenick.info');
insert into test.`user` (`id`, `userid`, `username`, `password`, `avatar`) values (1, 8565380, '朱鸿涛', 'sm', 'www.ardell-turner.co');
insert into test.`user` (`id`, `userid`, `username`, `password`, `avatar`) values (2, 6, '吴弘文', 'glL', 'www.cristobal-rempel.info');
2. 安装
database/sql 是Go操作数据库的标准库之一,它提供了一系列的接口方法,用于访问数据库(MySQL, SQLite, Oracle, PostgreSQL),它并不会提供数据库独有的方法,独有的方法由数据库驱动去实现。
在通常工作中,使用sqlx包来操作数据库,sqlx是基于标准sql的扩展,可以通过sqlx操作各种类型的数据,如将查询的数据转为结构体等。
go get "github.com/go-sql-driver/mysql"
go get "github.com/jmoiron/sqlx"
3. 使用
连接数据库
package main
import (
"fmt"
_ "github.com/go-sql-driver/mysql"
"github.com/jmoiron/sqlx"
)
func main() {
mysqlDB := connectMySQL()
defer mysqlDB.Close()
}
var (
userName string = "root"
password string = "root"
ipAddress string = "192.168.1.104"
port string = "3306"
dbName string = "test"
charset string = "utf8mb4"
)
// 连接数据库
func connectMySQL() *sqlx.DB {
dbstr := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=%s", userName, password, ipAddress, port, dbName, charset)
db, err := sqlx.Open("mysql", dbstr)
fmt.Println(err)
ping(db)
return db
}
func ping(DB *sqlx.DB) {
err := DB.Ping()
if nil != err {
fmt.Println("ping failed")
} else {
fmt.Println("ping success")
}
}
Exec增删改
package main
import (
"fmt"
"sqlx_demo/demo1"
"time"
)
func main() {
mysqlDB := demo1.ConnectMySQL()
defer mysqlDB.Close()
// mysqlDB
// Exec 执行SQL语句
insertSQL := "insert into user(userid, username, password, avatar, create_time, update_time) values (?,?,?,?,?,?)"
result, err := mysqlDB.Exec(insertSQL, 10000, "root", "123456", "avatar.png", time.Now(), time.Now())
if nil != err {
fmt.Println("数据插入失败", err)
return
}
id, _ := result.LastInsertId()
fmt.Println("数据插入成功, last id: ", id)
updateSQL := "update user set username = 'root' where id = 1"
result2, err := mysqlDB.Exec(updateSQL)
rowNum, _ := result2.RowsAffected()
fmt.Println("数据更新成功, affected rows: ", rowNum)
// 删除
deleteSQL := "delete from user where id = 2"
resul3, err := mysqlDB.Exec(deleteSQL)
rowNum, _ = resul3.RowsAffected()
fmt.Println("删除成功, affected rows:", rowNum)
}
Query查询
Query
方法返回的是一个sql.Rows类型的结果集,也可以用来查询多个字段的数据,不过需要定义多个字段的变量进行接收,迭代后者的next()方法,然后用Scan()
方法给对应类型变量赋值,以便取出结果,最后再把结果集关闭(释放连接)。
func main() {
mysqlDB := ConnectMySQL()
defer mysqlDB.Close()
querySQL := "select * from test.user"
rows, err := mysqlDB.Query(querySQL)
if err != nil {
fmt.Println("数据查询失败", err)
return
}
// rows
// rows.Next()
for rows.Next() {
var id, userid int
var username, password, avatar, create_time, update_time string
// rows.Scan
rows.Scan(&id, &userid, &username, &password, &avatar, &create_time, &update_time)
fmt.Println(id, userid, username, password, avatar, create_time, update_time)
}
rows.Close()
}
Get和Select方法
func (db *DB) Get(dest interface{}, query string, args ...interface{}) error
Get:将查询的一条记录,保存到结构体。
func (db *DB) Select(dest interface{}, query string, args ...interface{}) error
Select:将查询的多条记录保存的结构体的切片中。
func main() {
mysqlDB := ConnectMySQL()
defer mysqlDB.Close()
// 结构体的字段名首字母必须大写
type user struct {
Id int `db:"id"`
UserId int `db:"userid"`
UserName string `db:"username"`
Password string `db:"password"`
Avatar string `db:"avatar"`
CreateTime string `db:"create_time"`
UpdateTime string `db:"update_time"`
}
// 相当于var userData 后传入*user
userData := new(user)
mysqlDB.Get(userData, "select * from test.user where id = 3")
fmt.Println(userData)
var userSlice []user
// Select(指针)
err := mysqlDB.Select(&userSlice, "select * from test.user")
if nil != err {
fmt.Println(err)
}
for i := range userSlice {
fmt.Println(userSlice[i])
}
}
4. 线程池
4.1. 说明
只用sqlx.Open()
函数创建连接池,此时只是初始化了连接池,并没有连接数据库,连接时惰性的,只有调用sqlx.DB
的方法时,此时才真正用到了连接,连接池才会创建连接。
4.2. 配置
DB.SetMaxIdleConns(n int)
设置连接池中的保持连接的最大连接数,默认是0,表示连接池不会保持数据库连接的状态。
DB.SetMaxOpenConn(n int)
设置打开数据库的最大连接数,包含正在使用的连接和连接池的连接。默认值是0,表示无限制。
DB.SetConnMaxLifeTime(d time.Duration)
设置连接可以被使用的最长有效时间,如果过期,连接将被拒绝。
4.3. 数据库连接重试次数
sqldx中的方法帮我们做了很多事情,我们不用考虑连接失败的情况,当调用方法进行数据库操作的时候,如果连接失败,sqlx中的方法会帮我们处理,它会自动连接2次。
其他方法也有这种处理,变量maxBadConnRetries
是如果连接失败的尝试的次数,默认是2.