技术细节
这个问题让我很生气,我希望有人能帮忙。
我在golang中开发了一个应用程序,用于从postgres数据库中读取数据,并为每条记录发出一个http请求,然后更新数据库。
这很简单。但是,我们已经有了pgbouncer。我们对pgbouncer的配置是这样的,它不支持预准备语句。在一个准备好的语句中静默包装所有查询。围绕这个pgbouncer的方法是设置一个事务。对插入/更新/删除等事情来说,这一切都很好。
对于select语句,我将它包装在事务中:
func TransactionQuery(db *sql.DB, baseQuery string) (rows *sql.Rows, code int, err error) {
tx, txErr := db.Begin()
if txErr != nil {
return nil, -1, txErr
}
selectStmt, prepErr := tx.Prepare(baseQuery)
if prepErr != nil {
return nil, -1, fmt.Errorf("Failed to prepare statment: %s Error: %v", baseQuery, prepErr)
}
defer func() {
if stmtErr := selectStmt.Close(); stmtErr != nil {
rows = nil
code = -2
err = fmt.Errorf("Failed to close statement: %v.", stmtErr)
}
}()
rows, err = selectStmt.Query()
if err != nil {
fmt.Errorf("Failed to retrieve data: %v", err)
return nil, -1, err
}
return rows, 0, nil
}
(嗯,似乎已经缩小了一点点) AsS你可以看到我开始bnut没有关闭交易。这会导致pg方面出现问题,即每个选择都处于“处于事务处理中的空闲”状态。
我尝试了tx.Commit()和tx.Rollback(),在这两种情况下我都遇到了错误:
"unknown response for simple query '3'"
或
"unknown response for simple query 'D'"
何我成功关闭Go中的交易?我希望更新我们的pgbouncer.ini以允许我切换到驱动程序库的lib / pq,但我不确定这是否会直接帮助解决这个问题。
那么,我如何正确关闭tx对象,或者是否有办法强制Go不在引擎盖下使用预处理语句?
由于 森
我试图稍微改变一下:
func TransactionQuery(db *sql.DB, baseQuery string) (rows *sql.Rows, code int, err error) {
tx, txErr := db.Begin()
if txErr != nil {
return nil, -1, txErr
}
/*selectStmt, prepErr := tx.Prepare(baseQuery)
if prepErr != nil {
return nil, -1, fmt.Errorf("Failed to prepare statment: %s Error: %v", baseQuery, prepErr)
}
*/
rows, err = tx.Query(baseQuery)
if err != nil {
fmt.Errorf("Failed to retrieve data: %v", err)
return nil, -1, err
}
/* if stmtErr := selectStmt.Close(); stmtErr != nil {
rows = nil
code = -2
err = fmt.Errorf("Failed to close statement: %v.", stmtErr)
}*/
if txCloseErr := tx.Commit(); txErr != nil {
rows = rows
code = -3
err = txCloseErr
}
return rows, 0, nil
}
我在日志中看到的代码如下:
pq: unexpected describe rows response: '3'
但是,我应该指出,这是第二次尝试选择语句时。此应用程序选择批处理,处理它,然后选择后续批处理。第二次选择时会发生此错误。第一个选择没有问题。
答案 0 :(得分:2)
对于其他任何人来说,我已经解决了这个问题。
我的代码是将rows对象返回到上面的调用代码(未显示)。在读取行之前关闭事务似乎是问题的原因。我不完全理解为什么如此,请澄清你是否这样做。
现在我返回行和事务对象。然后当我读完所有行时,我回滚了事务。这可以保证一切正常。
由于 森
答案 1 :(得分:0)
Tx.Query返回sql.Rows的一个实例,它是结果集的游标。在迭代此游标时,不一定要检索数据。在迭代光标时,事务必须保持打开状态。
这就是为什么在事务关闭后你不能再迭代光标的原因。