操作MySQL之sqlx庫

BigSun丶發表於2024-03-14

目錄
  • 一、介紹和使用
    • 1. 安裝和快速使用
  • 二、基本增刪查改
    • 1. 增加資料
    • 2. 修改資料
    • 3. 刪除資料
    • 4. 查詢資料
  • 三、其他查詢
    • 1. Get和Select查詢
  • 四、其他方法
    • 1. sqlx的NamedExec
    • 2. sqlx的NamedQuery
  • 五、事務操作
  • 六、連線池

一、介紹和使用

  • 上一篇我們用了go-sql-driver/mysql庫來操作mysql,還有一個更優秀的庫sqlx,它也是對標準庫database/sql具體的實現,並進行進一步封裝和新增了一些方法

1. 安裝和快速使用

go get github.com/jmoiron/sqlx
package main

import (
	"fmt"
	_ "github.com/go-sql-driver/mysql" //執行一些初始化操作
	"github.com/jmoiron/sqlx"
)


func main() {

	//1 連結方式一
	DB,err:=sqlx.Open("mysql","root:123@tcp(127.0.0.1:3306)/lqz?charset=utf8")
	if err != nil {
		fmt.Println("連結出錯:",err)
	}
	defer DB.Close()
	err=DB.Ping()
	if err!=nil {
		fmt.Println("通訊出錯",err)
	}
	// 2 連結方式二
	//DB:=sqlx.MustOpen("mysql","root:123@tcp(127.0.0.1:3306)/lqz?charset=utf8")
	//defer DB.Close()
	//err:=DB.Ping()
	//if err!=nil {
	//	fmt.Println("通訊出錯",err)
	//}

}

二、基本增刪查改

  • 之前go-sql-driver/mysql庫的用法完全相容

1. 增加資料

// 1 增加資料
	sqlStr := "insert into music(name, year,sign_id) values (?,?,?)"
	ret, err := DB.Exec(sqlStr, "聽爸爸的話", 2023,1)
	if err != nil {
		fmt.Println("插入出錯",err)
		return
	}
	theID, err := ret.LastInsertId() // 新插入資料的id
	if err != nil {
		fmt.Println("獲取插入的id錯誤:",err)
		return
	}
	fmt.Println("插入成功,id為:", theID)

2. 修改資料

	// 2 修改資料
	sqlStr := "update music set name= ? where id = ?"
	ret, err := DB.Exec(sqlStr, "長大後我就成了你", 4)
	if err != nil {
		fmt.Println("更新失敗",err)
		return
	}
	n, err := ret.RowsAffected()
	if err != nil {
		fmt.Println("獲取影響的行數失敗:",err)
		return
	}
	fmt.Println("更新成功,影響行數為:",n)

3. 刪除資料

	// 3 刪除資料
	sqlStr := "delete from music where id = ?"
	ret, err := DB.Exec(sqlStr, 1)
	if err != nil {
		fmt.Println("刪除出錯:",err)
		return
	}
	n, err := ret.RowsAffected() // 操作影響的行數
	if err != nil {
		fmt.Println("獲取操作影響的行數出錯:",err)
		return
	}
	fmt.Println("刪除成功,影響的行數為:",n)

4. 查詢資料

// 4 查詢資料單條
	var music struct {
		Id     int
		Name   string
		Year   string
		SignId int
	}
	//QueryRow後一定要呼叫Scan方法,否則持有的資料庫連結不會被釋放
	err = DB.QueryRow("select * from music where id=?", 2).Scan(&music.Id, &music.Name, &music.Year, &music.SignId)
	if err != nil {
		fmt.Println("查詢出錯:", err)
	}
	fmt.Println(music)
	// 5 查詢多條
	sqlStr := "select * from music where id > ?"
	rows, err := DB.Query(sqlStr, 1)
	if err != nil {
		fmt.Println("查詢出錯:", err)
		return
	}
	// 關閉rows釋放持有的資料庫連結
	defer rows.Close()
	// 迴圈讀取結果集中的資料
	for rows.Next() {
		var m struct {
			Id     int
			Name   string
			Year   string
			SignId int
		}
		err := rows.Scan(&m.Id, &m.Name, &m.Year, &m.SignId)
		if err != nil {
			fmt.Println("遍歷出錯", err)
			return
		}
		fmt.Println(m)
	}

三、其他查詢

1. Get和Select查詢

	type Music struct {
		Id     int
		Name   string
		Year   string
		SignId int `db:"sign_id"`
	}
	var music Music
	err=DB.Get(&music,"select * from music where id=?", 2)
	if err != nil {
		fmt.Println("查詢出錯",err)
	}
	fmt.Println(music)
	// Select 查詢
	type Music struct {
		Id     int
		Name   string
		Year   string
		SignId int `db:"sign_id"`
	}
	var music []Music
	err=DB.Select(&music,"select * from music where id > ?", 2)
	if err != nil {
		fmt.Println("查詢出錯",err)
	}
	fmt.Println(music)

四、其他方法

1. sqlx的NamedExec

  • 傳參可使用key-value的形式,不用原來一個問號?對應一個引數
    用來繫結SQL語句與結構體或map中的同名欄位
sqlStr := "insert into music(name, year,sign_id) values (:name,:year,:sign_id)"
_, err = DB.NamedExec(sqlStr,
		map[string]interface{}{
			"name": "好漢歌",
			"year": 2024,
			"sign_id":1,
		})

2. sqlx的NamedQuery

  • 支援查詢
// 使用map作為查詢名	
type Music struct {
		Id     int
		Name   string
		Year   string
		SignId int `db:"sign_id"`
	}
	sqlStr := "SELECT * FROM music WHERE name=:name"
	// 使用map做命名查詢
	rows, _ := DB.NamedQuery(sqlStr, map[string]interface{}{"name": "好漢歌"})
	defer rows.Close()
	for rows.Next(){
		var m Music
		rows.StructScan(&m)
		fmt.Println(m)
	}
	// 使用結構體作為查詢名
type Music struct {
		Id     int
		Name   string
		Year   string
		SignId int `db:"sign_id"`
	}
	sqlStr := "SELECT * FROM music WHERE name=:name"
	// 使用結構體做命名查詢
	var music=Music{Name:"好漢歌"}
	rows, _ := DB.NamedQuery(sqlStr,music)
	defer rows.Close()
	for rows.Next(){
		var m Music
		rows.StructScan(&m)
		fmt.Println(m)
	}

五、事務操作

  • sqlx提供了db.Beginx()tx.Exec()方法進行事務操作
	tx, err := DB.Beginx() // 開啟事務
	if err != nil {
		fmt.Printf("開啟事務錯誤:%v\n", err)
		return
	}

	_,err=tx.Exec("insert into music(name, year,sign_id) values (?,?,?)", "聽奶奶的話",2023,1)
	if err != nil {
		tx.Rollback() // 出錯就回滾
		fmt.Println("出錯回滾")
		return
	}
	_,err=tx.Exec("insert into music(name, year,sign_id) values (?,?,?)", "聽爺爺的話")
	if err != nil {
		tx.Rollback() // 出錯就回滾
		fmt.Println("出錯回滾")
		return
	}
	tx.Commit()

六、連線池

  • 只用 sqlx.Open() 函式建立連線池,此時只是初始化了連線池,並沒有連線資料庫,連線都是惰性的,只有呼叫 sqlx.DB 的方法時,此時才真正用到了連線,連線池才會去建立連線,連線池很重要,它直接影響著你的程式行為

  • 連線池的工作原理也非常簡單,當呼叫 sqlx.DB 的方法時,會首先去向連線池請求要一個資料庫連線,如果連線池有空閒的連線,則返回給方法中使用,否則連線池將建立一個新的連線給到方法中使用;一旦將資料庫連線給到了方法中,連線就屬於方法了。方法執行完畢後,要不把連線所屬權還給連線池,要不傳遞給下一個需要資料庫連線的方法中,最後都使用完將連線釋放回到連線池中

db.SetMaxOpenConns(100) // 設定連線池最大連線數
db.SetMaxIdleConns(20)  // 設定連線池最大空閒連線數

相關文章