目錄
- 一、介紹和使用
- 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) // 設定連線池最大空閒連線數