Go 标准库
database/sql
提供了统一的数据库操作接口,支持通过第三方驱动访问多种数据库(如 MySQL、PostgreSQL、SQLite 等)。
一、安装数据库驱动
以 MySQL 和 PostgreSQL 为例:
# MySQL 驱动(github.com/go-sql-driver/mysql) go get github.com/go-sql-driver/mysql # PostgreSQL 驱动(github.com/lib/pq) go get github.com/lib/pq
二、连接数据库
1. MySQL 连接示例
import ( "database/sql" _ "github.com/go-sql-driver/mysql" ) db, err := sql.Open("mysql", "user:password@tcp(localhost:3306)/dbname") if err != nil { log.Fatal(err) } defer db.Close()
2. PostgreSQL 连接示例
import ( "database/sql" _ "github.com/lib/pq" ) db, err := sql.Open("postgres", "host=localhost user=postgres password=secret dbname=mydb sslmode=disable") if err != nil { log.Fatal(err) } defer db.Close()
✅
sql.Open
并不会立即建立连接,调用时不会报错。建议随后使用db.Ping()
验证连接是否成功。
三、基本操作
1. 查询单行数据(QueryRow)
var name string err := db.QueryRow("SELECT name FROM users WHERE id = ?", 1).Scan(&name) if err != nil { log.Fatal(err) } fmt.Println("用户名:", name)
2. 查询多行数据(Query)
rows, err := db.Query("SELECT id, name FROM users") if err != nil { log.Fatal(err) } defer rows.Close() for rows.Next() { var id int var name string rows.Scan(&id, &name) fmt.Println(id, name) }
3. 插入数据(Exec)
result, err := db.Exec("INSERT INTO users(name, age) VALUES(?, ?)", "Alice", 25) id, _ := result.LastInsertId() fmt.Println("新插入用户ID:", id)
4. 更新与删除
// 更新 _, err = db.Exec("UPDATE users SET age=? WHERE id=?", 30, 1) // 删除 _, err = db.Exec("DELETE FROM users WHERE id=?", 1)
四、使用预处理语句(Prepare)
stmt, err := db.Prepare("INSERT INTO users(name, age) VALUES(?, ?)") if err != nil { log.Fatal(err) } defer stmt.Close() _, err = stmt.Exec("Bob", 28)
优点:预编译可提升性能并增强安全性(防止 SQL 注入)。
五、事务操作(Transaction)
tx, err := db.Begin() if err != nil { log.Fatal(err) } _, err1 := tx.Exec("UPDATE accounts SET balance = balance - 100 WHERE id = 1") _, err2 := tx.Exec("UPDATE accounts SET balance = balance + 100 WHERE id = 2") if err1 != nil || err2 != nil { tx.Rollback() log.Fatal("事务失败,已回滚") } else { tx.Commit() fmt.Println("事务提交成功") }
六、错误处理与连接池
db.SetMaxOpenConns(10) db.SetMaxIdleConns(5) db.SetConnMaxLifetime(time.Hour)
- •
SetMaxOpenConns
: 最大连接数 - •
SetMaxIdleConns
: 最大空闲连接 - •
SetConnMaxLifetime
: 每个连接的最大可复用时间
七、常见注意事项
项目 | 建议说明 |
SQL注入 | 始终使用参数绑定或预编译语句 |
空结果处理 | QueryRow.Scan() 返回 sql.ErrNoRows 可判断为空 |
字段类型转换 | 注意 Go 类型与 SQL 类型的映射(如 time.Time 与 DATE) |
连接复用与释放 | 使用 defer rows.Close() 确保资源释放 |
八、封装数据库操作(推荐模式)
type User struct { ID int Name string Age int } func GetUserByID(db *sql.DB, id int) (*User, error) { user := User{} err := db.QueryRow("SELECT id, name, age FROM users WHERE id = ?", id).Scan( &user.ID, &user.Name, &user.Age, ) return &user, err }
九、小结
功能 | 描述 |
sql.Open |
建立数据库连接 |
Exec/Query |
执行 SQL 语句 |
Prepare |
预编译执行,提高效率与安全性 |
Transaction |
多操作原子性执行 |
Scan |
将 SQL 结果映射到 Go 变量 |