教程:访问关系型数据库
13 分钟阅读
Tutorial: Accessing a relational database - 教程:访问关系型数据库
本教程介绍了用Go和其标准库中的database/sql
包访问关系数据库的基本知识。
如果您对Go及其工具有基本的了解,那么您将从本教程中获益匪浅。如果这是您第一次接触Go,请参阅教程:开始使用go Tutorial: Get started with Go 的快速介绍。
您将使用的database/sql
包包含用于连接数据库、执行事务、取消正在进行的操作等的类型和函数。关于使用该包的更多细节,请参阅访问数据库。
在本教程中,您将创建一个数据库,然后编写代码来访问数据库。您的示例项目将是一个关于复古爵士乐唱片(vintage jazz records)的数据存储库。
在本教程中,您将通过以下几个部分进行学习:
- 为您的代码创建一个文件夹。
- 建立一个数据库。
- 导入数据库驱动程序。
- 获得数据库句柄并连接。
- 查询多行(记录)。
- 查询单行(记录)。
- 添加数据。
注意:关于其他教程,请参见 教程 Tutorials。
先决条件
- 安装MySQL关系型数据库管理系统(DBMS)。
- 安装 Go。有关安装说明,请参阅Installing Go。
- 编辑代码的工具。您拥有的任何文本编辑器都可以工作。
- 命令终端。在 Linux 和 Mac 上使用任何终端,以及在 Windows 上使用
PowerShell
或cmd
,Go 都能很好地工作。
为您的代码创建一个文件夹
首先,为您要写的代码创建一个文件夹。
a. 打开一个命令提示符,切换到您的主目录。
在Linux或Mac上:
|
|
在Windows上:
|
|
在本教程的其余部分,我们将显示$
作为提示符。我们使用的命令在Windows上也可以使用。
b. 在命令提示符下,为您的代码创建一个名为data-access
的目录。
|
|
c. 创建一个模块,您可以在其中管理您将在本教程中添加的依赖项。
运行go mod init
命令,给它您的新代码的模块路径。
|
|
该命令创建了一个go.mod
文件,您添加的依赖项将被列在其中以便追踪。更多信息,请务必参阅管理依赖项。
注意:在实际开发中,您会根据自己的需要指定一个更具体的模块路径。更多信息,请参见管理依赖项。
接下来,您将创建一个数据库。
建立一个数据库
在这一步,您将创建将要使用的数据库。您将使用DBMS本身的CLI来创建数据库和表,以及添加数据。
您将创建一个数据库,其中包含关于黑胶唱片的复古爵士乐(vintage jazz recordings on vinyl)的数据。
这里的代码使用MySQL CLI,但大多数DBMS都有自己的CLI,具有类似的功能。
打开一个新的命令提示符。
在命令行中,登录到您的DBMS,如下面MySQL的例子。
1 2 3 4
$ mysql -u root -p Enter password: mysql>
在
mysql
命令提示符下,创建一个数据库。1
mysql> create database recordings;
使用您刚创建的数据库,以便可以添加数据表。
1 2
mysql> use recordings; Database changed
在文本编辑器的
data-access
文件夹中,创建一个名为create-tables.sql
的文件,以保存用于添加数据表的SQL脚本。在该文件中,粘贴以下SQL代码,然后保存该文件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
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', 'John Coltrane', 63.99), ('Jeru', 'Gerry Mulligan', 17.99), ('Sarah Vaughan', 'Sarah Vaughan', 34.98);
在这个SQL代码中,您:
- 删除(drop)一个叫做
album
的表。如果您想重新开始处理这个表,可以先执行这条命令,这样就可以更容易地重新运行这个脚本。 - 创建一个有四列的
album
表:title
、artist
和price
。每一行的id
值都是由DBMS自动创建的。 - 添加四行记录。
- 删除(drop)一个叫做
mysql
命令提示符下,运行您刚刚创建的脚本。您将使用以下形式的
source
命令:1
mysql> source /path/to/create-tables.sql
在您的DBMS命令提示符下,使用
SELECT
语句来验证您已经成功创建了有数据的表。1 2 3 4 5 6 7 8 9 10
mysql> select * from album; +----+---------------+----------------+-------+ | id | title | artist | price | +----+---------------+----------------+-------+ | 1 | Blue Train | John Coltrane | 56.99 | | 2 | Giant Steps | John Coltrane | 63.99 | | 3 | Jeru | Gerry Mulligan | 17.99 | | 4 | Sarah Vaughan | Sarah Vaughan | 34.98 | +----+---------------+----------------+-------+ 4 rows in set (0.00 sec)
接下来,您将编写一些 Go 代码进行连接,以便可以查询。
查找并导入数据库驱动
现在您已经有了一个带有一些数据的数据库,开始编写您的Go代码吧。
找到并导入一个数据库驱动程序,它可以将您通过database/sql
包中的函数提出的请求转化为数据库能够理解的请求。
a. 在您的浏览器中,访问SQLDrivers wiki 页面,以确定您可以使用的驱动程序。
使用该页面上的列表来确定您要使用的驱动程序。在本教程中访问MySQL时,您将使用Go-MySQL-Driver。
b. 注意驱动程序的包名 —— 这里是github.com/go-sql-driver/mysql
。
c. 使用您的文本编辑器,创建一个文件来编写您的Go代码,并将该文件保存为main.go
,放在您先前创建的data-access
目录中。
d. 在main.go
中,粘贴以下代码以导入驱动程序包。
|
|
在这段代码中,您
- 将代码添加到
main
包中,以便可以独立执行。 - 导入MySQL驱动程序
github.com/go-sql-driver/mysql
。
导入驱动程序后,您将开始写代码来访问数据库。
获取数据库句柄并连接
现在编写一些Go代码,使用数据库句柄进行数据库访问。
您将使用一个指向 sql.DB
结构的指针,它代表对特定数据库的访问。
编写代码
a. 在main.go
中,在您刚刚添加的import
代码下面,粘贴以下Go代码来创建一个数据库句柄。
|
|
在这段代码中,您:
声明一个类型为*sql.DB的
db
变量。这是您的数据库句柄。 使
db
成为一个全局变量可以简化这个示例。在生产环境中,您会避免使用全局变量,比如把变量传递给需要它的函数,或者把它包装在一个结构中。使用MySQL驱动的Config —— 以及该类型的FormatDSN —— 来收集连接属性并将其格式化为连接字符串的
DSN
。Config
结构使得代码比连接字符串更容易阅读。调用 sql.Open 来初始化
db
变量,传递FormatDSN
的返回值。检查
sql.Open
是否有错误。如果数据库连接细节格式不正确,它可能会失败。为了简化代码,您要调用
log.Fatal
来结束执行,并将错误打印到控制台。在生产代码中,您会希望以一种更优雅的方式来处理错误。调用DB.Ping来确认连接到数据库是否有效。在运行时,
sql.Open
可能不会立即连接,这取决于驱动程序。您在这里使用Ping
来确认database/sql
包在需要时可以连接。检查
Ping
是否有错误,以防连接失败。如果
Ping
连接成功,则打印一条信息。
b. 在main.go
文件的顶部,就在包声明的下面,导入您需要的包,以支持您刚刚写的代码。
现在文件的顶部应该是这样的:
|
|
c. 保存main.go
。
运行代码
a. 开始跟踪MySQL驱动模块作为一个依赖项。
使用go get
来添加github.com/go-sql-driver/mysql
模块作为您自己模块的依赖。使用点参数
表示 “获取当前目录下代码的依赖项”。
|
|
Go下载了这个依赖项,因为您在上一步的import
声明中加入了它。关于依赖项跟踪的更多信息,请参见添加依赖项。
b. 在命令提示符下,设置 DBUSER
和 DBPASS
环境变量供 Go 程序使用。
在Linux或Mac上:
$ export DBUSER=username
$ export DBPASS=password
在Windows上:
|
|
c. 在包含main.go
的目录中的命令行中,通过输入go run
和一个点参数
来运行代码,表示 “在当前目录中运行软件包”。
|
|
您可以连接了! 接下来,您将查询一些数据。
查询多行(记录)
在本节中,您将使用Go来执行一个旨在返回多行的SQL查询。
对于可能返回多行的SQL语句,您可以使用database/sql
包中的Query
方法,然后循环浏览它所返回的行。(您将在稍后的单行查询一节中学习如何查询单行。)
编写代码
a. 在main.go
中,紧挨着func main
的上方,粘贴以下Album
结构的定义。您将用它来保存从查询中返回的行数据。
|
|
b. 在func main
下面,粘贴以下associatesByArtist
函数来查询数据库。
|
|
在这段代码中,您:
声明一个您定义的专辑类型的
albums
切片。这将保存来自返回行的数据。结构字段名和类型与数据库列名和类型相对应。使用DB.Query 执行一个
SELECT
语句来查询具有指定艺术家名字的专辑。
Query
的第一个参数是SQL语句。在该参数之后,您可以传递零个或多个任何类型的参数。这些参数为您提供了在SQL语句中指定参数值的地方。通过将SQL语句与参数值分开(而不是用例如fmt.Sprintf
连接),您可以使database/sql
包将参数值与SQL文本分开发送,从而消除任何SQL注入的风险。推迟关闭
rows
,这样当函数退出时,它持有的任何资源都会被释放。循环返回的行,使用
Rows.Scan
将每行的列值分配给Album
结构字段。
Scan
需要一个指向Go值的指针列表,列值将被写入其中。在这里,您把指针指向alb
变量中的(用&
操作符创建的)字段,。Scan
通过这些指针来更新结构字段。在循环中,检查将列值扫描到结构字段中的错误。
在循环中,将新的
alb
追加到albums
切片中。循环结束后,使用
rows.Err
检查整个查询是否有错误。注意,如果查询本身失败了,检查这里的错误是发现结果不完整的唯一方法。
c. 更新您的main
函数以调用 albumsByArtist
。
在func main
的结尾处,添加以下代码。
|
|
在新的代码中,您现在:
- 调用您添加的
albumsByArtist
函数,将其返回值分配给一个新的albums
变量。 - 打印结果。
运行该代码
从包含main.go
的目录中的命令行,运行代码。
|
|
接下来,您将查询单行。
查询单行(记录)
在本节中,您将使用Go来查询数据库中的单行。
对于最多返回一行的 SQL 语句,您可以使用QueryRow
,这比使用Query
循环更简单。
编写代码
a. 在 albumsByArtist
下方,粘贴以下 albumByID
函数。
|
|
在这段代码中,您:
使用
DB.QueryRow
来执行一个SELECT
语句,查询具有指定ID的专辑。它返回一个
sql.Row
。为了简化调用代码(您的代码!),QueryRow
并不返回错误。相反,它安排稍后从Rows.Scan
返回任何查询错误(如sql.ErrNoRows
)。使用Row.Scan将列值复制到结构字段。
检查来自
Scan
的错误。
特殊错误sql.ErrNoRows
表示查询没有返回任何行。通常情况下,这个错误值得用更具体的文本来代替,比如这里的 “no such album”。
b. 更新main
以调用 albumByID
。
在func main
的末尾,添加以下代码。
|
|
在新的代码中,您现在:
- 调用您添加的
albumByID
函数。 - 打印返回的album 的ID。
运行该代码
从包含main.go的目录中的命令行,运行代码。
|
|
接下来,您将在数据库中添加一个 album 。
添加数据
在本节中,您将使用Go来执行一个SQL INSERT
语句,向数据库添加新的行。
您已经看到了如何在返回数据的SQL语句中使用Query
和QueryRow
。要执行不返回数据的SQL语句,您可以使用Exec
。
编写代码
a. 在 albumByID
下面,粘贴以下 addAlbum
函数,在数据库中插入一个新album
,然后保存 main.go。
|
|
在这段代码中,您:
使用DB.Exec来执行一个
INSERT
语句。像
Query
一样,Exec
接收一个SQL语句,后面是该SQL语句的参数值。检查
INSERT
的尝试是否有错误。使用
Result.LastInsertId
检索插入的数据库行的ID。检查从检索ID的尝试中是否有错误。
b. 更新main以调用新的addAlbum
函数。
在func main
的末尾,添加以下代码。
|
|
在新的代码中,您现在:
- 用一个新
album
调用addAlbum
,将您要添加的album
的ID分配给albID
变量。
运行该代码
从包含main.go
的目录中的命令行,运行代码。
|
|
总结
祝贺您!您刚刚使用 Go 对关系数据库进行了简单的操作。
建议的下一个主题:
- 请看一下数据访问(Accessing Databases下的)指南,其中包含更多关于这里涉及到的主题的更多信息。
- 如果您是Go的新手,您会发现Effective Go和How to write Go code中描述了有用的最佳实践。
- go Tour是对Go基础知识的一个很好的逐步介绍。
完整的代码
本节包含您通过本教程构建的应用程序的代码。
|
|