• Golang 数据库操作


    在这里插入图片描述

    Install连接数据库需要的包

    go get -u github.com/go-sql-driver/mysql // MySQL数据库的包
    go get github.com/lib/pq // pg数据库的包
    
    • 1
    • 2

    注意:不同数据库,安装的包不同

    初始化连接

    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()
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    其中sql.DB是表示连接的数据库对象(结构体实例),它保存了数据库所有信息,内部维护了一个具有0到多个底层数据库连接池,它可以安全的被多个Goroutine使用。因此Open函数应该仅被调用一次,很少需要关闭这个对象

    连接池

    SetMaxOpenConns
    func (db *DB) SetMaxOpenConns(n int)
    
    • 1

    SetMaxOpenConns设置与数据库建立连接的最大数目。 如果n大于0且小于最大闲置连接数,会将最大闲置连接数减小到匹配最大开启连接数的限制。 如果n<=0,不会限制最大开启连接数,默认为0(无限制)。需要MySQL服务器的max_connections参数值要小,可以用以下SQL查询

    show variables like 'max_connections';
    
    • 1
    SetMaxIdleConns
    func (db *DB) SetMaxIdleConns(n int)
    
    • 1

    SetMaxIdleConns设置连接池中的最大闲置连接数。 如果n大于最大开启连接数,则新的最大闲置连接数会减小到匹配最大开启连接数的限制。 如果n<=0,不会保留闲置连接。需要比maxOpenConns小

    SetConnMaxIdleTime

    连接池里面的连接最大空闲时长(一个连接不活跃的时长)。

    SetConnMaxLifetime

    连接池里面的连接最大存活时长。必须要比mysql服务器设置的wait_timeout小,否则会导致golang侧连接池依然保留已被mysql服务器关闭了的连接。

    MySQL默认是8小时,可通过以下SQL查询

    show variables like 'wait_timeout';
    
    • 1

    查询数据

    单行数据查询

    通过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()
    	// 数据库使用完之后关闭连接
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67

    Go语言参数占位需要通过?进行占位 ,在执行SQL时将参数补充进去。

    顺序需要一致,例如:

    sqlStr := "select id, name, age from User where id=? and age=?"
    // 这里1表示传递给第一个?占位的参数(ID),2表示第二个(年龄)
    db, err := db.Query(sqlStr, 1, 18)
    
    • 1
    • 2
    • 3

    多行数据查询

    // 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)
    	}
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    插入数据

    插入、更新、删除数据都是使用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)
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    更新数据

    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)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    删除数据

    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)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    实现账号密码登录功能

    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("账号或者密码错误")
    	}
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74

    sqlx的部分用法

    安装

    go get github.com/jmoiron/sqlx
    
    • 1

    基本使用:

    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)
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
  • 相关阅读:
    Oracle 遍历变量游标
    Unable to load ‘@webpack-cli/serve‘ command问题解决
    Python网络爬虫与信息提取 第1周网络爬虫之规则 单元1:Requests库入门
    第七章 Java编程-多线程
    Oracle将归档日志从 ASM 拷贝到 Linux 文件系统中操作步骤
    音频占用磁盘空间太多 需要把mp3音频转aac音频缩小占用空间 应该怎么操作?
    C++socket网络编程实战http服务器(支持php)(上)
    ssh远程连接报错:WARNING: POSSIBLE DNS SPOOFING DETECTED(已解决)
    C++——pair用法总结
    远程连接问题1
  • 原文地址:https://blog.csdn.net/m0_46958731/article/details/134007735