Golang中如何使用pgxpool处理pgx的多行NoRowsError

Golang中如何使用pgxpool处理pgx的多行NoRowsError 大家好,

我是Darshan Hiranandani,目前正在一个使用 pgxpool 查询 PostgreSQL 数据库的项目中工作,我遇到了一个处理可能不返回任何行的查询时的问题。情况如下:

我使用的查询是:

SELECT * FROM invoices WHERE user_id = $1

这个查询返回一个 pgx.Rows 类型,其中包含查询结果以及任何相关的错误。问题是 pgx.Query() 在未找到行时不会返回错误,这让我无法区分空结果和实际错误。

我知道 pgx.QueryRow() 结合 pgxscan.ScanOne() 可以返回一个 NoRowsError,但这仅适用于你期望单行结果的情况。在我的场景中,我需要返回多行数据,所以这不适合我的用例。

根据我的了解,我应该使用 Rows.Next() 来检查是否存在下一行,如果不存在,它将返回 false。问题是当确实有行返回时,我不确定后续步骤。

有没有人遇到过这个问题,并且在处理 pgx 中的多行数据时找到了好的解决方法?任何建议或示例都将不胜感激。

提前感谢! 此致 Darshan Hiranandani


更多关于Golang中如何使用pgxpool处理pgx的多行NoRowsError的实战教程也可以访问 https://www.itying.com/category-94-b0.html

2 回复

user_id

user_id 不是唯一的吗?

更多关于Golang中如何使用pgxpool处理pgx的多行NoRowsError的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


pgx 中处理多行查询时,确实需要明确区分空结果集和查询错误。以下是处理这种情况的典型模式:

import (
    "context"
    "github.com/jackc/pgx/v5"
    "github.com/jackc/pgx/v5/pgxpool"
)

func GetInvoices(ctx context.Context, pool *pgxpool.Pool, userID int) ([]Invoice, error) {
    rows, err := pool.Query(ctx, "SELECT * FROM invoices WHERE user_id = $1", userID)
    if err != nil {
        return nil, err // 这是真正的查询错误
    }
    defer rows.Close()

    var invoices []Invoice
    for rows.Next() {
        var inv Invoice
        if err := rows.Scan(&inv.ID, &inv.UserID, &inv.Amount); err != nil {
            return nil, err // 扫描错误
        }
        invoices = append(invoices, inv)
    }

    // 检查迭代过程中是否有错误
    if err := rows.Err(); err != nil {
        return nil, err
    }

    // 如果 invoices 为空,表示没有找到行
    return invoices, nil
}

对于更复杂的场景,可以使用 pgxscan 简化扫描:

import "github.com/georgysavva/scany/v2/pgxscan"

func GetInvoicesScan(ctx context.Context, pool *pgxpool.Pool, userID int) ([]Invoice, error) {
    var invoices []Invoice
    err := pgxscan.Select(ctx, pool, &invoices, 
        "SELECT * FROM invoices WHERE user_id = $1", userID)
    
    if err != nil {
        // pgxscan 在查询错误时返回错误,空结果集返回 nil
        return nil, err
    }
    
    return invoices, nil
}

如果需要明确区分空结果和错误,可以创建自定义错误类型:

type NoRowsError struct {
    Msg string
}

func (e *NoRowsError) Error() string {
    return e.Msg
}

func GetInvoicesWithCustomError(ctx context.Context, pool *pgxpool.Pool, userID int) ([]Invoice, error) {
    rows, err := pool.Query(ctx, "SELECT * FROM invoices WHERE user_id = $1", userID)
    if err != nil {
        return nil, err
    }
    defer rows.Close()

    var invoices []Invoice
    for rows.Next() {
        var inv Invoice
        if err := rows.Scan(&inv.ID, &inv.UserID, &inv.Amount); err != nil {
            return nil, err
        }
        invoices = append(invoices, inv)
    }

    if err := rows.Err(); err != nil {
        return nil, err
    }

    if len(invoices) == 0 {
        return nil, &NoRowsError{Msg: "no invoices found for user"}
    }

    return invoices, nil
}

这种模式确保你能正确区分:

  1. 查询执行错误(连接问题、语法错误等)
  2. 行扫描错误
  3. 空结果集(零行返回)
回到顶部