文章目录
- 初始化连接
- 连接池
- SetMaxOpenConns
- SetMaxIdleConns
- SetConnMaxIdleTime
- SetConnMaxLifetime
- 查询数据
- 插入数据
- 更新数据
- 删除数据
- 实现账号密码登录功能
- sqlx的部分用法
首先安装包:Install
go get -u github.com/go-sql-driver/mysql // MySQL数据库的包
go get github.com/lib/pq // pg数据库的包
注意:不同数据库,安装的包不同
初始化连接
Open:函数只是验证连接参数是否正确
db.ping():测试是否能够正常连接数据库,返回nil
表示可以
全局定义db
变量是为了连t接数据库成功之后任意地方都可以进行操作。
引入 MySQL驱动包使用:_ "github.com/go-sql-driver/mysql"
当导入带有空白标识符前缀 _ 的包时,将调用包的 init 函数。该函数注册驱动程序
package main
import (
"database/sql"
"fmt"
_ "github.com/go-sql-driver/mysql"
)
// 定义全局db对象
var db *sql.DB
func InitDB() (err error) {
// Data Source Name:连接MySQL的格式
dsn := "root:password@tcp(127.0.0.1:3306)/GoStudy"
// 注意!!!这里不要使用:=,我们是给全局变量赋值,然后在main函数中使用全局变量db
db, err = sql.Open("mysql", dsn)
if err != nil {
return err
}
// 尝试与数据库建立连接(校验dsn是否正确)
return db.Ping()
}
func main() {
if err := InitDB(); err != nil {
fmt.Println("连接失败")
return
}
// 数据库使用完之后关闭连接
defer db.Close()
}
其中sql.DB
是表示连接的数据库对象(结构体实例),它保存了数据库所有信息,内部维护了一个具有0到多个底层数据库连接池,它可以安全的被多个Goroutine
使用。因此Open
函数应该仅被调用一次,很少需要关闭这个对象
连接池
SetMaxOpenConns
func (db *DB) SetMaxOpenConns(n int)
SetMaxOpenConns
设置与数据库建立连接的最大数目。 如果n大于0且小于最大闲置连接数,会将最大闲置连接数减小到匹配最大开启连接数的限制。 如果n<=0,不会限制最大开启连接数,默认为0(无限制)。需要MySQL服务器的max_connections参数值要小,可以用以下SQL查询
show variables like 'max_connections';
SetMaxIdleConns
func (db *DB) SetMaxIdleConns(n int)
SetMaxIdleConns设置连接池中的最大闲置连接数。 如果n大于最大开启连接数,则新的最大闲置连接数会减小到匹配最大开启连接数的限制。 如果n<=0,不会保留闲置连接。需要比maxOpenConns小
SetConnMaxIdleTime
连接池里面的连接最大空闲时长(一个连接不活跃的时长)。
SetConnMaxLifetime
连接池里面的连接最大存活时长。必须要比mysql服务器设置的wait_timeout小,否则会导致golang侧连接池依然保留已被mysql服务器关闭了的连接。
MySQL默认是8小时,可通过以下SQL查询
show variables like 'wait_timeout';
查询数据
单行数据查询
通过QueryRow
方法实现
package main
import (
"database/sql"
"fmt"
_ "github.com/go-sql-driver/mysql"
)
var db *sql.DB
type User struct {
Id int
Name string
Pwd string
Age int
Sex string
}
func InitDB() (err error) {
// Data Source Name:连接MySQL的格式
dsn := "root:password@tcp(127.0.0.1:3306)/GoStudy"
db, err = sql.Open("mysql", dsn)
if err != nil {
return err
}
return db.Ping()
}
// QueryRowData 查询单条数据
func QueryRowData() {
// 没有条件的SQL,默认查询第一条
sqlStr := "select id, name, age from User"
// 携带条件的SQL
//sqlStr := "select id, name, age from User where id=?"
var u User
err := db.QueryRow(sqlStr).Scan(&u.Id, &u.Name, &u.Age)
// 携带条件的SQL查询(2表示补充?占位的数据)
//err := db.QueryRow(sqlStr, 2).Scan(&u.Id, &u.Name, &u.age)
if err != nil {
fmt.Println("查询数据异常:", err)
return
}
fmt.Println(u.Id)
fmt.Println(u.Name)
fmt.Println(u.Age)
}
func main() {
if err := InitDB(); err != nil {
fmt.Println("连接失败")
return
}
defer db.Close()
fmt.Println("数据库连接成功")
//QueryRowData()
QueryData()
// 数据库使用完之后关闭连接
}
Go语言参数占位需要通过?
进行占位 ,在执行SQL时将参数补充进去。
顺序需要一致,例如:
sqlStr := "select id, name, age from User where id=? and age=?"
// 这里1表示传递给第一个?占位的参数(ID),2表示第二个(年龄)
db, err := db.Query(sqlStr, 1, 18)
多行数据查询
// QueryData 查询多条数据
func QueryData() {
// 这里可以增加条件判断
sqlStr := "select id, name, age from User"
rows, err := db.Query(sqlStr)
if err != nil {
fmt.Println("查询数据异常:", err)
}
// 关闭rows持有的数据库连接(一定要加)
defer rows.Close()
// 遍历查询的所有数据
for rows.Next() {
var u User
// 获取当前遍历到的数据
err2 := rows.Scan(&u.Id, &u.Name, &u.Age)
if err2 != nil {
fmt.Println("查询数据异常:", err2)
}
fmt.Println(u.Id, u.Name, u.Age)
}
}
插入数据
插入、更新、删除数据都是使用db.Exec
方法
func InsertData() {
sqlStr := "insert into User(name, age, sex) value(?,?,?)"
ret, err := db.Exec(sqlStr, "james", 18, "male")
if err != nil {
fmt.Println("数据库插入异常", err)
return
}
insertId, err2 := ret.LastInsertId()
if err2 != nil {
fmt.Println("插入数据ID获取失败:", err2)
return
}
fmt.Println("插入的数据ID:", insertId)
}
更新数据
func UpdateData() {
sqlStr := "update User set age=? where id=?"
ret, err := db.Exec(sqlStr, 33, 2)
if err != nil {
fmt.Println("数据更新失败", err)
return
}
n, err := ret.RowsAffected()
if err != nil {
fmt.Println("获取影响行数失败", err)
}
fmt.Println("数据更新成功,实际影响行数", n)
}
删除数据
func DeleteData() {
sqlStr := "delete from User where id=?"
ret, err := db.Exec(sqlStr, 2)
if err != nil {
fmt.Println("数据删除失败", err)
return
}
n, err := ret.RowsAffected()
if err != nil {
fmt.Println("获取影响行数失败", err)
}
fmt.Println("数据删除成功,实际影响行数", n)
}
实现账号密码登录功能
MySQL存储账号和密码信息,实现终端输入账号和密码,通过查询MySQL判断账号或者密码是否正确
package main
import (
"database/sql"
"fmt"
_ "github.com/go-sql-driver/mysql"
)
var db *sql.DB
type User struct {
Id int
Name string
}
// 初始化连接数据库
func InitDB() (err error) {
dsn := "root:password@tcp(127.0.0.1:3306)/GoStudy"
db, err = sql.Open("mysql", dsn)
if err != nil {
fmt.Println("DB link fail:", err)
return
}
return db.Ping()
}
// 查询账号和密码是否正确,返回bool类型
func QueryLogin(username, pwd string) bool {
sqlStr := "select id from User where `name`=? and `pwd`=?"
var u User
err := db.QueryRow(sqlStr, username, pwd).Scan(&u.Id)
if err != nil {
return false
}
return true
}
func main() {
if ping := InitDB(); ping != nil {
fmt.Println("DB ping fail:", ping)
return
}
var username, pwd string
fmt.Print("请输入账号:")
_, err := fmt.Scanln(&username)
if err != nil {
fmt.Println(err)
}
fmt.Print("请输入密码:")
_, err2 := fmt.Scanln(&pwd)
if err2 != nil {
fmt.Println(err)
}
isLogin := QueryLogin(username, pwd)
if isLogin {
fmt.Println("登录成功!!")
} else {
fmt.Println("账号或者密码错误")
}
}
sqlx的部分用法
安装
go get github.com/jmoiron/sqlx
基本使用:
package main
import (
"database/sql"
"fmt"
_ "github.com/go-sql-driver/mysql"
"github.com/jmoiron/sqlx"
)
var db *sqlx.DB
func InitDB() (err error) {
dsn := "root:password@tcp(127.0.0.1:3306)/GoStudy"
// sqlx:connect相当于 sqlx.open + db.ping
db, err = sqlx.Connect("mysql", dsn)
return err
}
type User struct {
Id int
Name sql.NullString
Age sql.NullInt16
// 避免查询出数据为Null导致的panic
Sex sql.NullString
Pwd sql.NullString
}
func UserInfoGet(sql string) User {
var u User
// 单条数据查询,查询出来的字段放到User结构体内
err := db.Get(&u, sql)
if err != nil {
fmt.Println("数据查询异常:", err)
}
return u
}
func UserSelect(sql string) []User {
// 多条数据查询,需要存放在数组内
var u []User
err := db.Select(&u, sql)
if err != nil {
fmt.Println("数据查询异常:", err)
}
return u
}
func main() {
if err := InitDB(); err != nil {
fmt.Println("数据库连接失败 ----")
} else {
fmt.Println("数据库连接成功 !!!!")
}
//u := UserInfoGet("select * from User")
//fmt.Println(u.Id)
u := UserSelect("select * from User")
for _, data := range u {
fmt.Println(data.Id, data.Name.String)
}
}