查询数据
6 分钟阅读
Querying for data - 查询数据
当执行返回数据的SQL语句时,使用database/sql
包中提供的Query
方法之一。这些方法中的每个都返回一个或多个Row
,你可以使用Scan
方法将这些数据复制到变量中。例如,你将使用这些方法来执行SELECT
语句。
当执行不返回数据的语句时,可以使用Exec
或ExecContext
方法代替。更多信息,请参阅Executing statements that don’t return data(执行不返回数据的语句)。
database/sql
包提供了两种执行查询以获取结果的方法。
- 查询单行 ——
QueryRow
最多从数据库返回一个Row
。更多信息,请参阅Querying for a single row (查询单行)。 - 查询多行 ——
Query
将所有匹配的行作为Rows
结构体返回,你的代码可以循环遍历它。更多信息,请参阅查询多行。
如果你的代码将重复执行相同的SQL语句,请考虑使用预处理语句。更多信息,请参阅Using prepared statements (使用预处理语句)。
注意:不要使用字符串格式化函数(如fmt.Sprintf)来组装SQL语句!你可能会引入SQL注入风险。更多信息,请参阅避免SQL注入风险。
查询单行
QueryRow
检索最多一个数据库行,例如当你想通过唯一ID查找数据时。如果查询返回多个行,Scan方法将丢弃除第一个之外的所有行。
QueryRowContext
的工作方式与QueryRow
相同,但有一个context.Context
参数。更多信息,请参阅Canceling in-progress operations(取消正在进行的操作)。
以下示例使用查询来确定是否有足够的库存来支持购买。如果有足够的库存,该SQL语句返回true
,如果没有则返回false
。Row.Scan通过指针将布尔返回值复制到enough
变量中。
|
|
注意:预处理语句中的参数占位符根据你使用的
DBMS
和驱动程序而异。例如,Postgres
的pq driver需要像$1
这样的占位符,而不是?
。
处理错误
QueryRow
本身不返回错误。相反,Scan
报告组合查找和扫描的任何错误。当查询找不到任何行时,它返回sql.ErrNoRows。
Functions for returning a single row 用于返回单行的函数
Function 函数 | Description 描述 |
---|---|
DB.QueryRow DB.QueryRowContext | 单独运行一个单行查询。 |
Tx.QueryRow Tx.QueryRowContext | 在较大的事务中运行一个单行查询。更多信息,请参阅Executing transactions (执行事务) 。 |
Stmt.QueryRow Stmt.QueryRowContext | 使用预处理语句运行一个单行查询。更多信息,请参见 Using prepared statements(使用预处理语句)。 |
Conn.QueryRowContext | 用于保留连接。更多信息,请参见Managing connections( 管理连接)。 |
查询多行
您可以使用Query
或QueryContext
查询多条记录,它们返回一个代表查询结果的Rows
。您的代码使用Rows.Next对返回的行进行迭代。每次迭代都会调用Scan
来将列值复制到变量中。
QueryContext
的工作方式与Query
类似,但有一个context.Context
实参。更多信息请参见 Canceling in-progress operations (取消正在进行的操作)。
下面的例子执行了一个查询,返回指定艺术家的专辑。这些专辑被返回到一个sql.Rows
中。该代码使用Rows.Scan将列值复制到由指针表示的变量中。
|
|
注意
注意:延迟调用的rows.Close。无论函数如何返回,这都会释放rows持有的任何资源。通过遍历所有行也会隐式地关闭它,但最好使用
defer
来确保无论发生什么情况,rows
都会被关闭。
注意:预处理语句中的参数占位符根据你使用的DBMS和驱动程序而异。例如,
Postgres
的pq driver需要一个类似于$1
的占位符,而不是?
。
处理错误
Be sure to check for an error from sql.Rows
after looping over query results. If the query failed, this is how your code finds out.
在循环查询结果后,一定要检查sql.Rows
的错误。如果查询失败,这就是你的代码如何发现的方式。
返回多行记录的函数
Function 函数 | Description 描述 |
---|---|
DB.Query DB.QueryContext | 单独运行一个查询。 |
Tx.Query Tx.QueryContext | 在较大的事务中运行一个查询。更多信息,请参阅Executing transactions (执行事务) 。 |
Stmt.Query Stmt.QueryContext | 使用预处理语句运行一个查询。更多信息,请参见Using prepared statements(使用预处理语句)。 |
Conn.QueryContext | 用于保留连接。更多信息,请参见Managing connections( 管理连接)。 |
处理可为null的列值
database/sql
包提供了几种特殊类型,你可以在Scan
方法中使用它们作为参数,当列的值可能为null
时。每个类型都包含一个Valid
字段,报告值是否非null
,以及一个字段(如果值为空),则持有该值。
以下示例中的代码查询客户名称。如果名称值为null
,则代码将另一个值替换为应用程序中使用的值。
|
|
在sql
包参考中可以查看每种类型的更多信息:
从列中获取数据
当遍历查询返回的行时,你可以使用Scan
将一行的列值复制到Go值中,如Rows.Scan参考中所述。
所有驱动程序都支持一组基本的数据转换,例如将SQL INT
转换为Go int
。一些驱动程序扩展了这组转换;有关详细信息,请参阅每个驱动程序的文档。
正如你可能期望的那样,Scan
将从与Go类型相似的列类型进行转换。例如,Scan
将从SQL CHAR
、VARCHAR
和TEXT
转换为Go string
。然而,Scan
还将执行到另一个适合列值的Go类型的转换。例如,如果列始终包含一个数字的VARCHAR
,你可以指定一个数值型的Go类型(如int
)来接收该值,然后Scan
将使用strconv.Atoi
为你进行转换。
有关Scan
方法进行的转换的更多详细信息,请参阅Rows.Scan参考。
处理多个结果集
当你的数据库操作可能返回多个结果集时,你可以使用Rows.NextResultSet来检索它们。例如,当你分别查询多个表并返回每个表的结果集时,这可能会很有用。
Rows.NextResultSet
准备下一个结果集,以便对Rows.Next
的调用可以从下一个集中检索第一行。它返回一个布尔值,表示是否确实存在下一个结果集。
以下示例中的代码使用DB.Query
执行两个SQL语句。第一个结果集来自存储过程的第一个查询,检索了album
表中的所有行。下一个结果集来自第二个查询,从song
表中检索行。
|
|