数据库操作
数据库连接
使用database/sql包连接和配置数据库。
package main
import (
"database/sql"
"fmt"
_ "github.com/go-sql-driver/mysql"
)
func main() {
// 配置数据库连接
dsn := "user:password@tcp(localhost:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local"
// 打开数据库连接
db, err := sql.Open("mysql", dsn)
if err != nil {
panic(err)
}
defer db.Close()
// 测试连接
err = db.Ping()
if err != nil {
panic(err)
}
// 配置连接池
db.SetMaxOpenConns(25)
db.SetMaxIdleConns(25)
db.SetConnMaxLifetime(5 * time.Minute)
fmt.Println("Database connected successfully")
}
基本CRUD操作
执行基本的增删改查操作。
package main
import (
"database/sql"
"fmt"
_ "github.com/go-sql-driver/mysql"
)
type User struct {
ID int
Name string
Email string
Password string
}
func main() {
db, err := sql.Open("mysql", "user:password@tcp(localhost:3306)/dbname")
if err != nil {
panic(err)
}
defer db.Close()
// 创建用户
result, err := db.Exec(
"INSERT INTO users (name, email, password) VALUES (?, ?, ?)",
"John Doe", "john@example.com", "password123",
)
if err != nil {
panic(err)
}
// 获取插入的ID
id, err := result.LastInsertId()
if err != nil {
panic(err)
}
// 查询用户
var user User
err = db.QueryRow("SELECT id, name, email FROM users WHERE id = ?", id).Scan(
&user.ID, &user.Name, &user.Email,
)
if err != nil {
panic(err)
}
// 更新用户
_, err = db.Exec(
"UPDATE users SET name = ? WHERE id = ?",
"John Updated", id,
)
if err != nil {
panic(err)
}
// 删除用户
_, err = db.Exec("DELETE FROM users WHERE id = ?", id)
if err != nil {
panic(err)
}
}
事务处理
使用事务确保数据一致性。
package main
import (
"database/sql"
"fmt"
_ "github.com/go-sql-driver/mysql"
)
func transferMoney(db *sql.DB, fromID, toID int, amount float64) error {
// 开始事务
tx, err := db.Begin()
if err != nil {
return err
}
// 如果发生错误,回滚事务
defer func() {
if p := recover(); p != nil {
tx.Rollback()
panic(p)
}
}()
// 从账户扣除金额
_, err = tx.Exec(
"UPDATE accounts SET balance = balance - ? WHERE id = ?",
amount, fromID,
)
if err != nil {
tx.Rollback()
return err
}
// 向账户增加金额
_, err = tx.Exec(
"UPDATE accounts SET balance = balance + ? WHERE id = ?",
amount, toID,
)
if err != nil {
tx.Rollback()
return err
}
// 提交事务
return tx.Commit()
}
func main() {
db, err := sql.Open("mysql", "user:password@tcp(localhost:3306)/dbname")
if err != nil {
panic(err)
}
defer db.Close()
err = transferMoney(db, 1, 2, 100.0)
if err != nil {
panic(err)
}
}
预处理语句
使用预处理语句提高性能和安全性。
package main
import (
"database/sql"
"fmt"
_ "github.com/go-sql-driver/mysql"
)
func main() {
db, err := sql.Open("mysql", "user:password@tcp(localhost:3306)/dbname")
if err != nil {
panic(err)
}
defer db.Close()
// 准备插入语句
stmt, err := db.Prepare("INSERT INTO users (name, email) VALUES (?, ?)")
if err != nil {
panic(err)
}
defer stmt.Close()
// 执行多次插入
users := []struct {
name string
email string
}{
{"Alice", "alice@example.com"},
{"Bob", "bob@example.com"},
{"Charlie", "charlie@example.com"},
}
for _, user := range users {
_, err = stmt.Exec(user.name, user.email)
if err != nil {
panic(err)
}
}
}
批量操作
使用批量操作提高性能。
package main
import (
"database/sql"
"fmt"
_ "github.com/go-sql-driver/mysql"
)
func main() {
db, err := sql.Open("mysql", "user:password@tcp(localhost:3306)/dbname")
if err != nil {
panic(err)
}
defer db.Close()
// 开始事务
tx, err := db.Begin()
if err != nil {
panic(err)
}
// 准备批量插入语句
stmt, err := tx.Prepare("INSERT INTO users (name, email) VALUES (?, ?)")
if err != nil {
tx.Rollback()
panic(err)
}
defer stmt.Close()
// 批量插入数据
for i := 0; i < 1000; i++ {
_, err = stmt.Exec(
fmt.Sprintf("User%d", i),
fmt.Sprintf("user%d@example.com", i),
)
if err != nil {
tx.Rollback()
panic(err)
}
}
// 提交事务
err = tx.Commit()
if err != nil {
panic(err)
}
}
连接池管理
优化数据库连接池配置。
package main
import (
"database/sql"
"fmt"
"time"
_ "github.com/go-sql-driver/mysql"
)
func configureConnectionPool(db *sql.DB) {
// 设置最大打开连接数
db.SetMaxOpenConns(25)
// 设置最大空闲连接数
db.SetMaxIdleConns(25)
// 设置连接最大生命周期
db.SetConnMaxLifetime(5 * time.Minute)
// 设置空闲连接最大生命周期
db.SetConnMaxIdleTime(10 * time.Minute)
}
func main() {
db, err := sql.Open("mysql", "user:password@tcp(localhost:3306)/dbname")
if err != nil {
panic(err)
}
defer db.Close()
// 配置连接池
configureConnectionPool(db)
// 监控连接池状态
go func() {
for {
stats := db.Stats()
fmt.Printf("Open Connections: %d\n", stats.OpenConnections)
fmt.Printf("In Use: %d\n", stats.InUse)
fmt.Printf("Idle: %d\n", stats.Idle)
fmt.Printf("Wait Count: %d\n", stats.WaitCount)
fmt.Printf("Wait Duration: %v\n", stats.WaitDuration)
time.Sleep(time.Second)
}
}()
}
错误处理
处理数据库操作中的常见错误。
package main
import (
"database/sql"
"fmt"
_ "github.com/go-sql-driver/mysql"
)
func handleDBError(err error) {
if err == sql.ErrNoRows {
fmt.Println("No rows found")
return
}
if err == sql.ErrConnDone {
fmt.Println("Connection is closed")
return
}
if err == sql.ErrTxDone {
fmt.Println("Transaction is already committed or rolled back")
return
}
// 处理其他错误
fmt.Printf("Database error: %v\n", err)
}
func main() {
db, err := sql.Open("mysql", "user:password@tcp(localhost:3306)/dbname")
if err != nil {
panic(err)
}
defer db.Close()
// 查询不存在的记录
var name string
err = db.QueryRow("SELECT name FROM users WHERE id = ?", 999).Scan(&name)
handleDBError(err)
// 使用已关闭的连接
db.Close()
err = db.Ping()
handleDBError(err)
// 使用已提交的事务
tx, _ := db.Begin()
tx.Commit()
err = tx.Commit()
handleDBError(err)
}