```
/*
* @Descripttion: golang 连接mysql demo
* @version:
* @Author: weilin
* @Date: 2019-10-19 11:31:23
* @LastEditors: weilin
* @LastEditTime: 2019-10-19 22:49:53
*/
package main
import (
// database/sql是golang的标准库之一,它提供了一系列接口方法,用于访问关系数据库。
//它并不会提供数据库特有的方法,那些特有的方法交给数据库驱动去实现。我们这里使用到的是mysql驱动
"database/sql"
"fmt"
"time"
// 导入mysql驱动
_ "github.com/go-sql-driver/mysql"
)
// 定义user结构体,也就是mysql表结构信息
type User struct {
ID int64 `db:"id"`
/**
在Go中读数据库比如rows.Scan的时候,有时会返回空值,如果直接把空值复制给string变量,会出错
这时就需要sql.NullString类型的变量了,它是一个结构体如下
type NullString struct {
String string
Valid bool // Valid is true if String is not NULL
}
*/
Name sql.NullString `db:"name"`
Age int `db:"age"`
}
// 定义mysql账号密码等信息
const (
USERNAME = "root"
PASSWORD = "1qaz2wsx"
NETWORK = "tcp"
SERVER = "localhost"
PORT = 3306
DATABASE = "tfbuilder"
)
func main() {
// 输出格式化的字符串。`Sprintf` 则格式化并返回一个字 符串而不带任何输出
dsn := fmt.Sprintf("%s:%s@%s(%s:%d)/%s", USERNAME, PASSWORD, NETWORK, SERVER, PORT, DATABASE)
/**
DB : 数据库对象。 sql.DB类型代表了数据库。和其他语言不一样,它并是数据库连接。
golang中的连接来自内部实现的连接池,连接的建立是惰性的,
当你需要连接的时候,连接池会自动帮你创建。通常你不需要操作连接池。一切都有go来帮你完成。
sql.Open: 第一个参数为驱动名,第二个参数为 用户名:密码@协议(ip:端口)/数据库
*/
DB, err := sql.Open("mysql", dsn)
if err != nil {
fmt.Printf("Open mysql failed,err:%v\n", err)
return
}
// 给db设置一个超时时间,时间小于数据库的超时时间即可
DB.SetConnMaxLifetime(100 * time.Second)
// 用于设置最大打开的连接数,默认值为0表示不限制。
DB.SetMaxOpenConns(100)
// 用于设置闲置的连接数
DB.SetMaxIdleConns(16)
queryOne(DB)
queryMulti(DB)
insertData(DB)
updateData(DB)
deleteData(DB)
}
//查询单行
func queryOne(DB *sql.DB) {
user := new(User)
// db.QueryRow()调用完毕后会将连接传递给sql.Row类型,当.Scan()方法调用之后把连接释放回到连接池。
// 查询单行数据
row := DB.QueryRow("select * from users where id=?", 1)
// 如果行不存在,则Scan()返回错误,需要处理异常,并绑定数据到结构体上
if err := row.Scan(&user.ID, &user.Name, &user.Age); err != nil {
fmt.Printf("scan failed, err:%v", err)
return
}
fmt.Println(*user)
}
//查询多行
func queryMulti(DB *sql.DB) {
user := new(User)
// 查询多行数据
// 会传递连接给 sql.Rows 对象,直到完全遍历了所有的行或
// Rows 的 Close 方法被调用了,连接才会返回给连接池。
rows, err := DB.Query("select * from users where id > ?", 1)
defer func() {
if rows != nil {
rows.Close()
}
}()
if err != nil {
fmt.Printf("Query failed,err:%v", err)
return
}
// rows.Next(),用于循环获取所有数据
for rows.Next() {
err = rows.Scan(&user.ID, &user.Name, &user.Age)
if err != nil {
fmt.Printf("Scan failed,err:%v", err)
return
}
fmt.Print(*user)
}
}
//插入数据
func insertData(DB *sql.DB) {
// Exec() 会将连接立马返回给连接池,但是它返回的 Result 对象会引用该连接,
// 所以,之后可能会再次被使用。数据库的insert,update采用Exec方法
// 通过db.Exec()插入数据,通过返回的err可知插入失败的原因,
// 通过返回的ret可以进一步查询本次插入数据影响的行数RowsAffected和最后插入的Id(如果数据库支持查询最后插入Id).
result, err := DB.Exec("insert INTO users(name,age) values(?,?)", "YDZ", 23)
if err != nil {
fmt.Printf("Insert failed,err:%v", err)
return
}
// 最后插入的Id
lastInsertID, err := result.LastInsertId()
if err != nil {
fmt.Printf("Get lastInsertID failed,err:%v", err)
return
}
fmt.Println("LastInsertID:", lastInsertID)
// 本次插入数据影响的行数
rowsaffected, err := result.RowsAffected()
if err != nil {
fmt.Printf("Get RowsAffected failed,err:%v", err)
return
}
fmt.Println("RowsAffected:", rowsaffected)
}
//更新数据,注释同上
func updateData(DB *sql.DB) {
result, err := DB.Exec("UPDATE users set age=? where id=?", "30", 3)
if err != nil {
fmt.Printf("Insert failed,err:%v", err)
return
}
rowsaffected, err := result.RowsAffected()
if err != nil {
fmt.Printf("Get RowsAffected failed,err:%v", err)
return
}
fmt.Println("RowsAffected:", rowsaffected)
}
//删除数据,注释同上
func deleteData(DB *sql.DB) {
result, err := DB.Exec("delete from users where id=?", 1)
if err != nil {
fmt.Printf("Insert failed,err:%v", err)
return
}
rowsaffected, err := result.RowsAffected()
if err != nil {
fmt.Printf("Get RowsAffected failed,err:%v", err)
return
}
fmt.Println("RowsAffected:", rowsaffected)
}
/**
而通常工作中我们可能更多的是用https://github.com/jmoiron/sqlx包来操作数据库,sqlx是基于标准库database/sql的扩展,并且我们可以通过sqlx操作各种类型的数据
参考: https://www.cnblogs.com/hanyouchun/p/6708037.html
https://www.jianshu.com/p/06f26f879d61
https://www.cnblogs.com/zhaof/p/8509164.html
*/
```
有疑问加站长微信联系(非本文作者)