返回首页 - Notes - 2017

Go 操作关系数据库


概述

Go 中,我们通过使用标准库中的 database/sql 包来操作关系数据库

除了 database/sql 包,每一种具体的数据库还得引入一个对应的驱动包

下面是常见数据库的驱动包列表

各个驱动注册的连接标识符不一样

各个驱动查询语句中使用的占位符不一样

下面以 MySQL 数据库为例,基本的引入语句为:

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

连接数据库

// 数据库用户名:数据库密码@连接方式(连接参数)/数据库名
db, err := sql.Open("mysql", "root:root@tcp(127.0.0.1:3306)/hello")
if err != nil {
  log.Fatal(err)
}
defer db.Close()

查询单条记录

查询单条记录使用 QueryRow 方法

package main

import (
  "database/sql"
  "fmt"
  "log"

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

type User struct {
  id   int
  name string
}

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

  // 声明一个 user 变量
  var user User

  // 查询一条记录
  err = db.QueryRow("select id, name from users where id = ?", 1).Scan(&user.id, &user.name)
  if err != nil {
    log.Fatal(err)
  }

  fmt.Println(user)
}

查询多条记录

查询多条记录使用 Query 方法

package main

import (
  "database/sql"
  "fmt"
  "log"

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

type User struct {
  id   int
  name string
}

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

  // 声明一个 user 变量和数组
  var user User
  var users []User

  // 查询多条记录
  rows, err := db.Query("select id, name from users")
  if err != nil {
    log.Fatal(err)
  }
  defer rows.Close() // 记得在函数退出前关闭连接

  // 迭代每一行记录
  for rows.Next() {
    err := rows.Scan(&user.id, &user.name)
    if err != nil {
      log.Fatal(err)
    }
    // 将得到的每一行数据存进数组
    users = append(users, user)
  }

  fmt.Println(users)
}

缓存查询语句

如果一个查询语句要多次用到,可以用 Prepare 方法缓存起来,该方法会返回一个 Stmt 对象

Stmt 对象上面同样可以选择调用 QueryRow 或是 Query

package main

import (
  "database/sql"
  "fmt"
  "log"

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

type User struct {
  id   int
  name string
}

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

  // 声明一个 user 变量和数组
  var user User
  var users []User

  // 缓存查询语句
  stmt, err := db.Prepare("select id, name from users where id = ? or id = ?")
  if err != nil {
    log.Fatal(err)
  }
  defer stmt.Close()

  // 执行一次具体的查询操作
  rows, err := stmt.Query(1, 2)
  if err != nil {
    log.Fatal(err)
  }
  defer rows.Close()

  for rows.Next() {
    err := rows.Scan(&user.id, &user.name)
    if err != nil {
      log.Fatal(err)
    }
    users = append(users, user)
  }

  fmt.Println(users)
}

新增、删除、修改

增、删、改操作,使用 Exec 方法

package main

import (
  "database/sql"
  "fmt"
  "log"

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

type User struct {
  id   int
  name string
}

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

  // 缓存语句
  stmt, err := db.Prepare("insert into users (name) values (?)")
  if err != nil {
    log.Fatal(err)
  }
  defer stmt.Close()

  // 执行具体的操作
  res, err := stmt.Exec("张三")
  if err != nil {
    log.Fatal(err)
  }

  // 获取该操作最后插入的那条记录的自增 ID
  lastId, err := res.LastInsertId()
  if err != nil {
    log.Fatal(err)
  }

  // 获取该操作影响的记录数
  rowCount, err := res.RowsAffected()
  if err != nil {
    log.Fatal(err)
  }

  fmt.Printf("最后一条记录的 ID 是 %d,影响 %d 行\n", lastId, rowCount)
}

使用事务

使用 db.Begin() 开始一个事务,db.Begin() 会返回一个 Tx 对象,后续的一切查询、执行操作都在这个 Tx 对象上进行

最后使用 Tx.Commit() 提交事务,或使用 Tx.Rollback() 回滚事务

package main

import (
  "database/sql"
  "fmt"
  "log"

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

type User struct {
  id   int
  name string
}

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

  // 开始事务
  tx, err := db.Begin()
  if err != nil {
    log.Fatal(err)
  }

  // 在事务上使用缓存语句
  stmt, err := tx.Prepare("insert into users (name) values (?)")
  if err != nil {
    log.Fatal(err)
  }
  defer stmt.Close()

  // 执行具体的操作
  res, err := stmt.Exec("马六")
  if err != nil {
    log.Fatal(err)
  }

  // 提交事务
  tx.Commit()
}

date:2017-07-09