golang连接MySQL数据库
安装配置mysql驱动
安装驱动
go get -u github.com/go-sql-driver/mysql
初始化模块
go mod init 模块名称
执行go mod tidy
go mod tidy
导入驱动
import (
"database/sql"
_ "github.com/go-sql-driver/mysql"
)
获得数据库连接
获得连接
package main
import (
"database/sql"
_ "github.com/go-sql-driver/mysql"
"time"
)
func main() {
db, err := sql.Open("mysql", "username:password@/dbname")
if err != nil {
panic(err)
}
print(db)
// 最大连接时长
db.SetConnMaxLifetime(time.Minute * 3)
// 最大连接数
db.SetMaxOpenConns(10)
// 空闲连接数
db.SetMaxIdleConns(10)
}
初始化连接
Open函数可能只是验证其参数格式是否正确,实际上并不创建与数据库的连接。如果要检查数据源的名称是否真实有效,应该调用Ping方法。
返回的DB对象可以安全地被多个goroutine并发使用,并且维护其自己的空闲连接池。因此,Open函数应该仅被调用一次,很少需要关闭这个DB对象。
package main
import (
"fmt"
"database/sql"
_ "github.com/go-sql-driver/mysql"
)
// 定义一个全局对象db
var db *sql.DB
// 定义一个初始化数据库的函数
func initDB() (err error) {
dsn := "username:password@tcp(ip:port)/dbname?charset=utf8mb4&parseTime=True"
// 不会校验账号密码是否正确
db, err = sql.Open("mysql", dsn)
if err != nil {
return err
}
// 尝试与数据库建立连接(校验dsn是否正确)
err = db.Ping()
if err != nil {
return err
}
return nil
}
func main() {
err := initDB() // 调用输出化数据库的函数
if err != nil {
fmt.Printf("初始化失败!,err:%v\n", err)
return
}else{
fmt.Printf("初始化成功")
}
}
数据库操作
查询操作
单行查询
单行查询db.QueryRow()执行一次查询,并期望返回最多一行结果(即Row)。QueryRow总是返回非nil的值,直到返回值的Scan方法被调用时,才会返回被延迟的错误。
// 查询一条用户数据
func queryOneRow() {
sql := "SQL查询语句"
var s struct{
attr1 type
attr2 type
...
}{
}
// 确保QueryRow之后调用Scan方法,否则持有的数据库链接不会被释放
err := db.QueryRow(sql, args1, args2...).Scan(&s.attr1, &s.attr2...)
if err != nil {
fmt.Printf("scan failed, err:%v\n", err)
return
}
fmt.Printf("attr1:%v attr:%v...\n", s.attr1, s.attr2...)
}
例子:
u := struct {
id int
username string
password string
}{
}
sql := "select id, username, password from t_user where id=?"
err := db.QueryRow(sql, 1).Scan(&u.id, &u.username, &u.password)
查询多行
多行查询db.Query()执行一次查询,返回多行结果(即Rows),一般用于执行select命令。参数args表示query中的占位参数。
// 查询多条数据示例
func queryMultiRow() {
sql := "SQL查询语句"
rows, err := db.Query(sql, args1, args2...)
if err != nil {
fmt.Printf("query failed, err:%v\n", err)
return
}
// 非常重要:关闭rows释放持有的数据库链接
defer rows.Close()
// 循环读取结果集中的数据
for rows.Next() {
var s struct{
attr1 type
attr2 type
...
}{
}
err := rows.Scan(&s.attr1, &s.attr2...)
if err != nil {
fmt.Printf("scan failed, err:%v\n", err)
return
}
fmt.Printf("attr1:%v attr:%v...\n", s.attr1, s.attr2...)
}
}
例子:
sqlStr := "select id, username, password from user_tbl where id > ?"
rows, err := db.Query(sqlStr, 0)
defer rows.Close()
for rows.Next() {
u := struct {
id int
username string
password string
}{
}
err := rows.Scan(&u.id, &u.username, &u.password)
}
插入、更新、删除数据
插入、更新、删除操作都使用Exec方法。
func (db *DB) Exec(query string, args ...interface{
}) (Result, error)
// 插入、更新、删除数据
func operateData() {
sql := "SQL插入、更新和删除语句"
ret, err := db.Exec(sql, args1, args2...)
if err != nil {
fmt.Printf("operate failed, err:%v\n", err)
return
}
rows, err := ret.RowsAffected() //操作影响的行数
//theID, err := ret.LastInsertId() // 新插入数据的id
if err != nil {
fmt.Printf("operate failed, err:%v\n", err)
return
}
fmt.Printf("operate success, the number of rows is %d.\n", rows)
}