Golang中如何使用pgx在返回多行的查询中返回NoRowsErr
Golang中如何使用pgx在返回多行的查询中返回NoRowsErr
在我的当前项目中,我使用 pgxpool 通过以下查询语句查询数据库:“query(ctx, SELECT * FROM invoices WHERE user_id = $1, id)”。
此函数返回一个 pgx.Rows 类型,它保存查询结果值和一个错误类型。
如果存在错误,则不会返回 pgx.Rows 的值。
然而,实际情况并非如此,因为 pgx.Query() 函数对于无结果行的情况不会返回错误。
在这种情况下,函数既不返回错误,也不返回 pgx.Rows 类型的值。
只有 pgx.QueryRow() 结合 pgxscan.ScanOne() 才能为你返回 NoRowsError。
问题是 pgx.ScanOne() 只返回一行,而我想返回多行。
根据我在网上搜集的信息,我应该使用 Rows.Next() 来检查下一行是否存在,否则当没有行时它会返回 false。然而,当查询确实返回行时,我不确定应该怎么做。
我当前的实现:
func ReadInvoicesByUserID(id int) ([]*Invoice, fields.GrammarError) {
ctx, db := bikeshop.Connect()
defer db.Close()
var tempInv Invoice
var invoices []*Invoice
_, fieldErr := ReadInvoices()
if fieldErr.ErrMsgs != nil &&
strings.Contains(fieldErr.ErrMsgs[0], "failed to connect to `user=username") {
fmt.Printf("ReadInvoicesByUserID funct: error username doesn't exist")
return nil, fieldErr
}
rows, err := db.Query(ctx, `SELECT * FROM invoices WHERE user_id = $1`, id)
if !rows.Next() {
// if no rows were found thats an NoRowsError
if rows.Err() == nil {
fmt.Println("Found an Error Iterating in Getting All the Invoices for the Specified User")
fieldErr.AddMsg(fields.ResourceNotFound, "no rows in result set")
return nil, fieldErr
}
return nil, fieldErr
}
// err := pgxscan.ScanAll(&invs, rows)
// var err error
for rows.Next() {
fmt.Println("Processing Query in ReadInvoicesbyUserID")
err = pgxscan.ScanOne(&tempInv, rows)
if errors.Is(err, pgx.ErrNoRows) {
fmt.Println("Found an Error Iterating in Getting All the Invoices for the Specified User")
break
}
invoices = append(invoices, &tempInv)
}
if rows.Err() != nil {
fmt.Println("Found an Error Iterating in Getting All更多关于Golang中如何使用pgx在返回多行的查询中返回NoRowsErr的实战教程也可以访问 https://www.itying.com/category-94-b0.html
这种行为并非此包独有——任何 SQL 数据库通常都是这样实现的。如果你要求“给我一行数据”,那么在没有行的情况下就会报错。
但 SELECT * ... 是在要求“给我找到的任何行”。在大多数情况下,你并不知道会得到多少行,零行也是一个有效的结果。通常,你可以正常继续处理,并在后续流程中处理这种情况。在 Web 应用程序中,你的前端可能只会收到一个空列表作为所有发票的查询结果,并可以显示“未找到发票”。
如果你确实想在此阶段抛出错误,最简单的方法可能是在 for 循环之后,直接添加一行 if len(invoices) == 0 { return nil, fmt.Errorf(...) }。
if len(invoices) == 0 { return nil, fmt.Errorf(...) }
更多关于Golang中如何使用pgx在返回多行的查询中返回NoRowsErr的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
在pgx中处理多行查询的ErrNoRows情况,正确的做法是检查rows.Next()的返回值和rows.Err()。以下是修正后的实现:
func ReadInvoicesByUserID(id int) ([]*Invoice, fields.GrammarError) {
ctx, db := bikeshop.Connect()
defer db.Close()
var invoices []*Invoice
rows, err := db.Query(ctx, `SELECT * FROM invoices WHERE user_id = $1`, id)
if err != nil {
// 处理查询执行错误
fmt.Printf("Query error: %v\n", err)
fieldErr := fields.GrammarError{}
fieldErr.AddMsg(fields.DatabaseError, err.Error())
return nil, fieldErr
}
defer rows.Close()
// 检查是否有行返回
if !rows.Next() {
// 检查是否有扫描错误
if rows.Err() != nil {
fmt.Printf("Rows error: %v\n", rows.Err())
fieldErr := fields.GrammarError{}
fieldErr.AddMsg(fields.DatabaseError, rows.Err().Error())
return nil, fieldErr
}
// 没有错误但没有数据行
fmt.Println("No invoices found for user")
fieldErr := fields.GrammarError{}
fieldErr.AddMsg(fields.ResourceNotFound, "no invoices found")
return []*Invoice{}, fieldErr
}
// 处理第一行
var inv Invoice
err = rows.Scan(&inv.ID, &inv.UserID, &inv.Amount /* 其他字段 */)
if err != nil {
fmt.Printf("Scan error: %v\n", err)
fieldErr := fields.GrammarError{}
fieldErr.AddMsg(fields.DatabaseError, err.Error())
return nil, fieldErr
}
invoices = append(invoices, &inv)
// 处理剩余行
for rows.Next() {
var inv Invoice
err = rows.Scan(&inv.ID, &inv.UserID, &inv.Amount /* 其他字段 */)
if err != nil {
fmt.Printf("Scan error: %v\n", err)
fieldErr := fields.GrammarError{}
fieldErr.AddMsg(fields.DatabaseError, err.Error())
return nil, fieldErr
}
invoices = append(invoices, &inv)
}
// 检查迭代过程中是否有错误
if rows.Err() != nil {
fmt.Printf("Rows iteration error: %v\n", rows.Err())
fieldErr := fields.GrammarError{}
fieldErr.AddMsg(fields.DatabaseError, rows.Err().Error())
return nil, fieldErr
}
return invoices, fields.GrammarError{}
}
如果你使用pgxscan简化扫描过程,可以这样实现:
func ReadInvoicesByUserID(id int) ([]*Invoice, fields.GrammarError) {
ctx, db := bikeshop.Connect()
defer db.Close()
var invoices []*Invoice
rows, err := db.Query(ctx, `SELECT * FROM invoices WHERE user_id = $1`, id)
if err != nil {
fmt.Printf("Query error: %v\n", err)
fieldErr := fields.GrammarError{}
fieldErr.AddMsg(fields.DatabaseError, err.Error())
return nil, fieldErr
}
defer rows.Close()
// 使用pgxscan.ScanAll
err = pgxscan.ScanAll(&invoices, rows)
if err != nil {
fmt.Printf("ScanAll error: %v\n", err)
fieldErr := fields.GrammarError{}
fieldErr.AddMsg(fields.DatabaseError, err.Error())
return nil, fieldErr
}
// 检查是否没有数据
if len(invoices) == 0 {
fmt.Println("No invoices found for user")
fieldErr := fields.GrammarError{}
fieldErr.AddMsg(fields.ResourceNotFound, "no invoices found")
return []*Invoice{}, fieldErr
}
return invoices, fields.GrammarError{}
}
关键点:
db.Query()执行成功但无数据时不会返回错误- 必须调用
rows.Next()来检查是否有数据行 - 使用
rows.Err()检查扫描过程中的错误 - 总是使用
defer rows.Close()确保资源释放 - 对于空结果集,返回空切片和适当的错误信息

