建议你先看这篇文章《【数据库】原生 go 与 MySql 的基本示例》,熟悉基本的 go 如何连接 MySql,及一些基本的配置,同时我也会使用该篇文章中已经创建好的数据库和数据表。
环境配置- go1.17
- MySql8.0
- 已经存在的一个数据库:bookInfo
- 已经存在的一个数据表:books
在 database/sql 这个官方包中提供了 Exec 和 ExecContext (该方法提供了 context.Context 用于上下文的选择,可以取消正在进行的操作)两个方法用于执行基本的插入,删除和更新操作,官方文档中将其视为“不返回数据的”操作。
关于 Exec 的插入示例
func addBook(book Book) (int64, error) {
// 注意,这里使用的查询语句是 MySql 的,不同的数据库在执行 Exec 时,内部查询语句可能不一样
res, err := db.Exec("insert into books (title, author, price) values (?, ?, ?)", book.Title, book.Author, book.Price)
if err != nil {
return 0, fmt.Errorf("新增书籍 %s 出错,错误为 %v", book.Title, err)
}
// LastInsertId 返回插入数据的 id 值
id, err := res.LastInsertId()
if err != nil {
return 0, fmt.Errorf("返回 id 出错,错误为 %v", err)
}
return id, nil
}
查询
在 database/sql 这个官方包中提供了 Query,QueryContext(可以取消正在执行的操作),QueryRow(一般用于查询 id,因为 id 是唯一的) 和 QueryRowContext(同样可以取消正在执行的操作) 两个方法用于执行基本的查询。
- 请求到的数据可以通过 Scan 方法将其读取到你的变量中。
- 对于多行数据,可以用 Next 方法进行遍历。
查询多行返回数据:通过 Query 来查询一个作者下的多个书籍信息
func findBooksByAuthor(name string) ([]Book, error) {
// 书籍结构体
// 包含了 ID,Title,Author,Price 字段
var books []Book
rows, err := db.Query("SELECt * FROM books WHERe author = ?", name)
if err != nil {
return nil, fmt.Errorf("查询作者 %q 时出错:%v", name, err)
}
defer rows.Close()
// 循环遍历这个连接
for rows.Next() {
var book Book
// Scan 将当前行中所有数据复制到对应的数据结构中
err := rows.Scan(&book.ID, &book.Title, &book.Author, &book.Price)
if err != nil {
return nil, fmt.Errorf("遍历作者书籍 %q 时出错:%v", name, err)
}
// 将一行书籍信息添加至书籍切片中
books = append(books, book)
}
// Err 返回迭代期间遇到的错误
if err := rows.Err(); err != nil {
return nil, fmt.Errorf("遍历作者书籍 %q 时出错:%v", name, err)
}
return books, nil
}
查询单行返回数据:通过 QueryRow 来查询一个 id 对应的书籍信息。
func findBookById(id int64) (Book, error) {
var book Book
// QueryRow 只会返回一行数据
row := db.QueryRow("SELECt * FROM books WHERe id = ?", id)
// Scan 将当前行中所有数据复制到对应的数据结构中
err := row.Scan(&book.ID, &book.Title, &book.Author, &book.Price)
if err == sql.ErrNoRows {
return book, fmt.Errorf("没有 ID 为 %d 对应的书籍,错误是:%v", id, err)
}
return book, nil
}
【注】QueryRow 本身不返回任何错误,Scan 会返回错误,其中和返回数据相关的错误只有一个,就是sql.ErrNoRows表示没有查询到信息
复用数据库操作语句如果你存在多处复用相同的数据库操作语句,不妨使用 sql.Stmt来实现。
func preParedStatement(id int) Book {
// 准备预制语句
stmt, err := db.Prepare("select * from books where id =?")
if err != nil {
log.Fatal("db.Prepare", err)
}
var book Book
// 通过提供 id 来满足占位符 ? 需要的数据
err = stmt.QueryRow(id).Scan(&book.ID, &book.Title, &book.Author, &book.Price)
if err != nil {
if err == sql.ErrNoRows {
log.Fatal("stmt.QueryRow(id).Scan", err)
}
return book
}
return book
}
在 main.go 中我们可以得到结果
// 预制语句
book := preParedStatement(2)
fmt.Println(book) // {2 鹿川有许多粪 李沧东 58}
参考
Executing SQL statements that don’t return data
Querying for data
Using prepared statements



