go data_error ai_generated true

sql: Rows are closed, cannot call LastInsertId on result

ID: go/sql-rows-err-lastinsertid

Also available as: JSON · Markdown · 中文
80%Fix Rate
85%Confidence
1Evidence
2024-01-10First Seen

Version Compatibility

VersionStatusIntroducedDeprecatedNotes
Go 1.15 active
Go 1.16 active
Go 1.17 active
Go 1.18 active
Go 1.19 active
Go 1.20 active
Go 1.21 active
Go 1.22 active
Go 1.23 active

Root Cause

Calling Result.LastInsertId() on a sql.Result from an INSERT that used a SELECT or RETURNING clause, or after rows have been consumed.

generic

中文

对来自使用 SELECT 或 RETURNING 子句的 INSERT 的 sql.Result 调用 Result.LastInsertId(),或在行已被消耗后调用。

Official Documentation

https://pkg.go.dev/database/sql#Result.LastInsertId

Workarounds

  1. 90% success Use db.Exec() for INSERT statements without RETURNING; use db.QueryRow() with RETURNING and scan into a variable
    Use db.Exec() for INSERT statements without RETURNING; use db.QueryRow() with RETURNING and scan into a variable
  2. 85% success Access LastInsertId immediately after Exec() before any rows iteration
    Access LastInsertId immediately after Exec() before any rows iteration
  3. 80% success For PostgreSQL with RETURNING, use a separate SELECT currval() or lastval() query
    For PostgreSQL with RETURNING, use a separate SELECT currval() or lastval() query

中文步骤

  1. Use db.Exec() for INSERT statements without RETURNING; use db.QueryRow() with RETURNING and scan into a variable
  2. Access LastInsertId immediately after Exec() before any rows iteration
  3. For PostgreSQL with RETURNING, use a separate SELECT currval() or lastval() query

Dead Ends

Common approaches that don't work:

  1. 90% fail

    Rows.Close() closes the result set, making LastInsertId unavailable; order is wrong.

  2. 60% fail

    db.Exec() returns a Result that supports LastInsertId, but if the INSERT has a RETURNING clause, it still fails.

  3. 95% fail

    The result is tied to the original query; reconnecting doesn't recover the last insert ID.