Go+Postgres使用QueryRow遇pq错误:unexpected Parse response 'C'
解决 pq: unexpected Parse response 'C' 错误
问题分析
你遇到的pq: unexpected Parse response 'C'错误,虽常与未关闭*sql.Rows相关,但你使用的是QueryRow返回的*sql.Row(无Close方法)。核心问题出在事务上下文里,当QueryRow返回sql.ErrNoRows时,底层PostgreSQL连接的结果集未被完全消费——同一事务复用的连接残留上一次查询的状态,导致后续查询的协议交互冲突,触发驱动解析错误。
解决方案
替换查询部分的QueryRow为Query,手动控制rows的关闭,确保每次查询的结果集被彻底清理:
type Queryable interface { Query(query string, args ...interface{}) (*sql.Rows, error) QueryRow(query string, args ...interface{}) *sql.Row } func GetOrCreateArticle(q Queryable, article *entity.Article) (id int64, err error) { const selectQuery string = "SELECT id FROM articles WHERE link = $1" const insertQuery string = "INSERT INTO articles (link, title) VALUES ($1, $2) RETURNING id" // 使用Query替代QueryRow,手动管理rows生命周期 rows, err := q.Query(selectQuery, article.Link) if err != nil { return 0, err } defer rows.Close() // 确保无论执行结果如何,rows都会被关闭 // 读取查询结果 found := false for rows.Next() { if err := rows.Scan(&id); err != nil { return 0, err } found = true } // 检查rows遍历过程中的错误 if err := rows.Err(); err != nil { return 0, err } // 未找到则执行插入 if !found { err = q.QueryRow(insertQuery, article.Link, article.Title).Scan(&id) } return id, err }
关键说明
Query返回的*sql.Rows必须通过defer rows.Close()手动关闭,即使无查询结果,也能确保底层连接的结果集被完全清理,避免事务内连接状态异常。- 遍历
rows.Next()后必须检查rows.Err(),捕获遍历过程中可能出现的隐性错误。 - 插入操作仍用
QueryRow即可,因为插入仅返回单行结果,无需手动管理rows。
内容的提问来源于stack exchange,提问作者nem0z
相关产品推荐
相关产品推荐

