在go语言里访问sql数据库,一般都是用 database/sql 这个包

Overview

访问db使用 sql.DB,使用这个类型可以创建statements, transactions,执行查询和获取结果。但需要注意,sql.DB不是一个数据库连接。

sql.DB完成的任务:

  • 依赖驱动去打开和关闭真正的数据库连接
  • 按需管理连接池

数据库驱动

进行任何数据库操作都需要先引入驱动包:

import (
    "database/sql"
    _ "github.com/go-sql-driver/mysql"
)

这里匿名地引入了一个mysql驱动包,下划线符号使驱动包中的任何符号都在该文件中不可见。

建立连接

先上代码:

func main() {
    db, err := sql.Open("mysql", "user:password@tcp(127.0.0.1:3306)/hello")
    if err != nil {
        log.Fatal(err)
    }
    defer db.Close()
}

以上:

  • Open语句的第一个参数指定数据库类型,还可以使用 github.com/mattn/go-sqlite3 或 github.com/lib/pq
  • Open语句的第二个参数指定数据库连接信息
  • 记得必须要进行错误处理
  • 使用defer 安全关闭连接

如果需要延迟连接数据库,可以先检查数据库能否连接成功,如下:

err = db.Ping()
if err != nil {
    /// do something here
}

不要频繁的打开和关闭数据库,最好,为每个数据库只创建一个 sql.DB,如果需要使用就传过去就行了。
如果不合理使用sql.DB,就会很快耗尽网络资源,或挤压很多处于 TIME_WAIT状态的连接。

从数据库获取数据

var (
    id int
    name string
)
rows, err := db.Query("select id, name from users where id = ?", 1)
if err != nil {
    log.Fatal(err)
}
defer rows.Close()
for rows.Next() {
    err := rows.Scan(&id, &name)
    if err != nil {
        log.Fatal(err)
    }
    log.Println(id, name)
}
err = rows.Err()
if err != nil {
    log.Fatal(err)
}

prepare查询

stmt, err := db.Prepare("select id, name from users where id = ?")
if err != nil {
        log.Fatal(err)
}
defer stmt.Close()
rows, err := stmt.Query(1)
if err != nil {
        log.Fatal(err)
}
defer rows.Close()
for rows.Next() {
        // ...
}
if err = rows.Err(); err != nil {
        log.Fatal(err)
}

单行查询

var name string
err = db.QueryRow("select name from users where id = ?", 1).Scan(&name)
if err != nil {
        log.Fatal(err)
}
fmt.Println(name)

prepare单行查询

stmt, err := db.Prepare("select name from users where id = ?")
if err != nil {
        log.Fatal(err)
}
var name string
err = stmt.QueryRow(1).Scan(&name)
if err != nil {
        log.Fatal(err)
}
fmt.Println(name)

更新数据

stmt, err := db.Prepare("INSERT INTO users(name) VALUES(?)")
if err != nil {
        log.Fatal(err)
}
res, err := stmt.Exec("Dolly")
if err != nil {
        log.Fatal(err)
}
lastId, err := res.LastInsertId()
if err != nil {
        log.Fatal(err)
}
rowCnt, err := res.RowsAffected()
if err != nil {
        log.Fatal(err)
}
log.Printf("ID = %d, affected = %d\n", lastId, rowCnt)

注意不要用 query更新数据,即使你不关心返回结果,看下面两个句子,一对一错:

_, err := db.Exec("DELETE FROM users")  // OK
_, err := db.Query("DELETE FROM users") // BAD

事务

本文翻译自: Go database/sql tutorial