在开始之前,你需要确保自己安装了Golang的编程环境,安装MySQL数据库,有一个可以用于编写代码的编辑器或IDE工具。我在这里使用的编辑器是Fleet。
将下面的SQL语句在MySQL中执行,创建数据库并插入数据.。
drop table if exists album;
create table album (
id int auto_increment not null,
title varchar(128) not null,
artist varchar(255) not null,
price decimal(5,2) not null,
primary key (`id`)
);
insert into album
(title, artist, price)
values
('Blue Train', 'John Coltrane', 56.99),
('Giant Steps', 'Greey Mulligan', 63.99),
('Jeru', 'Gerry Mulligan', 17.99),
('Sarah Vaughan', 'Sarah Vaughan', 34.98);
进入终端,输入以下命令。(当然,你也可以手动创建)
mkdir data-access
cd ./data-access
go mod init example/data-access
在上面创建的目录下创建文件main.go,将以下代码粘贴到文件中。
package main
import (
"database/sql"
"errors"
"fmt"
"github.com/go-sql-driver/mysql"
"log"
)
终端输入以下命令下载上面代码中引入的MySQL的驱动包
go mod tidy
在main.go中输入以下代码,连接数据库。
var db *sql.DB
func main() {
// 设置连接属性
cfg := mysql.Config{
User: "root",
Passwd: "123456",
Net: "tcp",
Addr: "127.0.0.1:3306",
DBName: "recordings",
}
// 获取数据库句柄
var err error
db, err = sql.Open("mysql", cfg.FormatDSN())
if err != nil {
log.Fatal(err)
}
// 测试是否连接成功
pingErr := db.Ping()
if pingErr != nil {
log.Fatal(pingErr)
}
log.Println("Connected!")
}
对于数据库中的数据,我们需要定义一个结构体去接收。在main.go中输入以下代码。
// Album 记录实体结构体
type Album struct {
ID int64
Title string
Artist string
Price float32
}
接着我们实现String函数让输出稍微美观一些。
func (album Album) String() string {
return fmt.Sprintf(`{ "id": %d, "title": %q, "artist": %q, "price": %.2f }`, album.ID, album.Title, album.Artist, album.Price)
}
接下来,让我们编写一个函数,这个函数的功能是通过人名去查询数据库中的记录。
// 通过人名查询记录
func albumsByArtist(name string) ([]Album, error) {
var albums []Album
rows, err := db.Query("select * from album where artist = ?", name)
if err != nil {
return nil, fmt.Errorf("albumsByArtist %q: %v", name, err)
}
// 资源释放,defer关键字修饰的语句在其下方语句未执行完成前不会执行
defer rows.Close()
// 循环获取相关值
for rows.Next() {
var alb Album
if err := rows.Scan(&alb.ID, &alb.Title, &alb.Artist, &alb.Price); err != nil {
return nil, fmt.Errorf("albumsByArtist %q: %v", name, err)
}
albums = append(albums, alb)
}
if err := rows.Err(); err != nil {
return nil, fmt.Errorf("albumsByArtist %q: %v", name, err)
}
return albums, nil
}
接着定义一个函数,通过id去查询记录。
// 通过ID查询记录
func albumsById(id int64) (Album, error) {
var alb Album
row := db.QueryRow("select * from album where id = ?", id)
if err := row.Scan(&alb.ID, &alb.Title, &alb.Artist, &alb.Price); err != nil {
if errors.Is(err, sql.ErrNoRows) {
return alb, fmt.Errorf("albumsById %d: no such album", id)
}
return alb, fmt.Errorf("albumsById %d: %v", id, err)
}
return alb, nil
}
然后,我们在main函数中调用。
// 查询数据
albums, err := albumsByArtist("John Coltrane")
if err != nil {
log.Fatal(err)
}
log.Printf("Albums found: %v\n", albums)
alb, err := albumsById(2)
if err != nil {
log.Fatal(err)
}
log.Printf("Album found: %v\n", alb)
我们来定义一个函数用来修改数据,用id做为删选条件。
// 修改数据
func updateAlbumById(alb Album) (int64, error) {
result, err := db.Exec("update album set title = ?, artist = ?, price = ? where id = ?", alb.Title, alb.Artist, alb.Price, alb.ID)
if err != nil {
return 0, fmt.Errorf("updateAlbumById: %v", err)
}
rows, err := result.RowsAffected()
if err != nil {
return 0, fmt.Errorf("updateAlbumById: %v", err)
}
return rows, nil
}
在main函数中调用它。
// 修改数据
updateRows, err := updateAlbumById(Album{
ID: 1,
Title: "White teddy bear",
Artist: "John Thompson's",
Price: 20.99,
})
if err != nil {
log.Fatal(err)
}
log.Printf("Number of rows updated: %v\n", updateRows)
定义一个函数用来插入数据并且返回插入数据在数据库中的id。
// 插入记录
func addAlbum(alb Album) (int64, error) {
result, err := db.Exec("insert into album (title, artist, price) values (?, ?, ?)", alb.Title, alb.Artist, alb.Price)
if err != nil {
return 0, fmt.Errorf("addAlbum: %v", err)
}
id, err := result.LastInsertId()
if err != nil {
return 0, fmt.Errorf("addAlbum: %v", err)
}
return id, nil
}
在main函数中调用
// 插入数据
albId, err := addAlbum(Album{
Title: "The Modern Sound of Betty Carter",
Artist: "Betty Carter",
Price: 49.99,
})
if err != nil {
log.Fatal(err)
}
log.Printf("id of added alnum: %v\n", albId)
定义一个函数用来删除数据。
// 删除记录,返回删除的行数
func deleteAlbum(id int64) (int64, error) {
result, err := db.Exec("delete from album where id = ?", id)
if err != nil {
return 0, fmt.Errorf("deleteAlbum: %v", err)
}
rows, err := result.RowsAffected()
if err != nil {
return 0, fmt.Errorf("deleteAlbum: %v", err)
}
return rows, nil
}
在main函数中调用
// 删除数据
deleteRows, err := deleteAlbum(albId)
if err != nil {
log.Fatal(err)
}
log.Printf("Number of rows deleted: %v\n", deleteRows)
对于数据库的操作完成后,需要释放数据库连接,在main函数中输入以下代码释放资源。
// 释放资源
err = db.Close()
if err != nil {
log.Fatal(err)
}
完整代码如下。
package main
import (
"database/sql"
"errors"
"fmt"
"github.com/go-sql-driver/mysql"
"log"
)
var db *sql.DB
// Album 记录实体结构体
type Album struct {
ID int64
Title string
Artist string
Price float32
}
func (album Album) String() string {
return fmt.Sprintf(`{ "id": %d, "title": %q, "artist": %q, "price": %.2f }`, album.ID, album.Title, album.Artist, album.Price)
}
func main() {
// 设置连接属性
cfg := mysql.Config{
User: "root",
Passwd: "123456",
Net: "tcp",
Addr: "127.0.0.1:3306",
DBName: "recordings",
}
// 获取数据库句柄
var err error
db, err = sql.Open("mysql", cfg.FormatDSN())
if err != nil {
log.Fatal(err)
}
// 测试是否连接成功
pingErr := db.Ping()
if pingErr != nil {
log.Fatal(pingErr)
}
log.Println("Connected!")
// 查询数据
albums, err := albumsByArtist("John Coltrane")
if err != nil {
log.Fatal(err)
}
log.Printf("Albums found: %v\n", albums)
alb, err := albumsById(2)
if err != nil {
log.Fatal(err)
}
log.Printf("Album found: %v\n", alb)
// 修改数据
updateRows, err := updateAlbumById(Album{
ID: 1,
Title: "White teddy bear",
Artist: "John Thompson's",
Price: 20.99,
})
if err != nil {
log.Fatal(err)
}
log.Printf("Number of rows updated: %v\n", updateRows)
// 插入数据
albId, err := addAlbum(Album{
Title: "The Modern Sound of Betty Carter",
Artist: "Betty Carter",
Price: 49.99,
})
if err != nil {
log.Fatal(err)
}
log.Printf("id of added alnum: %v\n", albId)
// 删除数据
deleteRows, err := deleteAlbum(albId)
if err != nil {
log.Fatal(err)
}
log.Printf("Number of rows deleted: %v\n", deleteRows)
// 释放资源
err = db.Close()
if err != nil {
log.Fatal(err)
}
}
// 通过人名查询记录
func albumsByArtist(name string) ([]Album, error) {
var albums []Album
rows, err := db.Query("select * from album where artist = ?", name)
if err != nil {
return nil, fmt.Errorf("albumsByArtist %q: %v", name, err)
}
// 资源释放,defer关键字修饰的语句在其下方语句未执行完成前不会执行
defer rows.Close()
// 循环获取相关值
for rows.Next() {
var alb Album
if err := rows.Scan(&alb.ID, &alb.Title, &alb.Artist, &alb.Price); err != nil {
return nil, fmt.Errorf("albumsByArtist %q: %v", name, err)
}
albums = append(albums, alb)
}
if err := rows.Err(); err != nil {
return nil, fmt.Errorf("albumsByArtist %q: %v", name, err)
}
return albums, nil
}
// 通过ID查询记录
func albumsById(id int64) (Album, error) {
var alb Album
row := db.QueryRow("select * from album where id = ?", id)
if err := row.Scan(&alb.ID, &alb.Title, &alb.Artist, &alb.Price); err != nil {
if errors.Is(err, sql.ErrNoRows) {
return alb, fmt.Errorf("albumsById %d: no such album", id)
}
return alb, fmt.Errorf("albumsById %d: %v", id, err)
}
return alb, nil
}
// 修改数据
func updateAlbumById(alb Album) (int64, error) {
result, err := db.Exec("update album set title = ?, artist = ?, price = ? where id = ?", alb.Title, alb.Artist, alb.Price, alb.ID)
if err != nil {
return 0, fmt.Errorf("updateAlbumById: %v", err)
}
rows, err := result.RowsAffected()
if err != nil {
return 0, fmt.Errorf("updateAlbumById: %v", err)
}
return rows, nil
}
// 插入记录
func addAlbum(alb Album) (int64, error) {
result, err := db.Exec("insert into album (title, artist, price) values (?, ?, ?)", alb.Title, alb.Artist, alb.Price)
if err != nil {
return 0, fmt.Errorf("addAlbum: %v", err)
}
id, err := result.LastInsertId()
if err != nil {
return 0, fmt.Errorf("addAlbum: %v", err)
}
return id, nil
}
// 删除记录,返回删除的行数
func deleteAlbum(id int64) (int64, error) {
result, err := db.Exec("delete from album where id = ?", id)
if err != nil {
return 0, fmt.Errorf("deleteAlbum: %v", err)
}
rows, err := result.RowsAffected()
if err != nil {
return 0, fmt.Errorf("deleteAlbum: %v", err)
}
return rows, nil
}