Golang 数据库操作

文章目录

      • 初始化连接
      • 连接池
        • SetMaxOpenConns
        • SetMaxIdleConns
        • SetConnMaxIdleTime
        • SetConnMaxLifetime
      • 查询数据
      • 插入数据
      • 更新数据
      • 删除数据
      • 实现账号密码登录功能
      • sqlx的部分用法

Golang 数据库操作_第1张图片

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)
	}
}

你可能感兴趣的:(1024程序员节,golang,数据库,开发语言,后端)