Golang中ORA-01000错误:超出最大打开游标数的问题解决
Golang中ORA-01000错误:超出最大打开游标数的问题解决 我有一个运行堆栈的服务。为此,它通过在Oracle中执行查询来读取这个堆栈。问题是,执行几个小时后,我收到以下消息:
ORA-01000: 超出最大打开游标数
我想知道可能是什么原因。我有一个用于打开连接的全局变量,我总是检查其连接状态并将其复制到局部变量。
根据我的理解,在 Rows.Next() 中,当它检查到没有更多行时会关闭游标,所以我不应该累积这么多游标以至于超出限制。
数据库连接:
type GERENCIACON struct {
DataBase *sql.DB
}
func (gc *GERENCIACON) F_FECHAR_CONEXAO() {
gc.DataBase.Close()
}
func (gc *GERENCIACON) F_ABRIR_CONEXAO() {
if gc.DataBase == nil || gc.DataBase.Ping() != nil {
gc.DataBase, _ = sql.Open("goracle", "X/X@10.0.254.10:1521/orcl")
}
}
var VGGerenciaConexao GERENCIACON
用于查询的结构体:
type GERENCIACONSULTA struct {
DataBase *sql.DB
Rows *sql.Rows
}
func (gc *GERENCIACONSULTA) F_EXECUTA_CONSULTA(pSql string) {
VGGerenciaConexao.F_ABRIR_CONEXAO()
gc.DataBase = VGGerenciaConexao.DataBase
gc.Rows, _ = gc.DataBase.Query(pSql)
}
服务获取堆栈:
var vGerenciaConsulta CertanoLabsPackage.GERENCIACONSULTA
var vSQL string
for {
vSQL = "select * from stack "
vGerenciaConsulta.F_EXECUTA_CONSULTA(vSQL)
for vGerenciaConsulta.Rows.Next() {
...
}
time.Sleep(time.Minute)
}
可能是什么问题呢?
更多关于Golang中ORA-01000错误:超出最大打开游标数的问题解决的实战教程也可以访问 https://www.itying.com/category-94-b0.html
将数据库连接的打开和关闭操作移出循环。
更多关于Golang中ORA-01000错误:超出最大打开游标数的问题解决的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
在调用 vGerenciaConsulta.Rows.Next() 时可能发生错误,导致其返回 false 并退出循环。在这种情况下,Close() 不会被自动调用。
这是一个典型的游标泄漏问题。你的代码没有正确关闭 sql.Rows 对象,导致数据库游标一直保持打开状态。
主要问题在于:
GERENCIACONSULTA.F_EXECUTA_CONSULTA方法执行查询后没有处理可能的错误- 循环中没有关闭
Rows对象 - 没有使用
defer确保资源释放
这是修复后的代码示例:
type GERENCIACONSULTA struct {
DataBase *sql.DB
Rows *sql.Rows
}
func (gc *GERENCIACONSULTA) F_EXECUTA_CONSULTA(pSql string) error {
VGGerenciaConexao.F_ABRIR_CONEXAO()
gc.DataBase = VGGerenciaConexao.DataBase
var err error
gc.Rows, err = gc.DataBase.Query(pSql)
return err
}
func (gc *GERENCIACONSULTA) F_FECHAR_CONSULTA() {
if gc.Rows != nil {
gc.Rows.Close()
gc.Rows = nil
}
}
// 服务代码修改
var vGerenciaConsulta CertanoLabsPackage.GERENCIACONSULTA
var vSQL string
for {
vSQL = "select * from stack"
err := vGerenciaConsulta.F_EXECUTA_CONSULTA(vSQL)
if err != nil {
// 处理错误
continue
}
// 确保Rows被关闭
defer vGerenciaConsulta.F_FECHAR_CONSULTA()
for vGerenciaConsulta.Rows.Next() {
// 处理数据
}
// 显式关闭当前查询的Rows
vGerenciaConsulta.F_FECHAR_CONSULTA()
time.Sleep(time.Minute)
}
更健壮的实现应该使用上下文并确保每次迭代都清理资源:
func processStack() error {
for {
ctx := context.Background()
VGGerenciaConexao.F_ABRIR_CONEXAO()
if VGGerenciaConexao.DataBase == nil {
return fmt.Errorf("database connection is nil")
}
rows, err := VGGerenciaConexao.DataBase.QueryContext(ctx, "select * from stack")
if err != nil {
return fmt.Errorf("query failed: %w", err)
}
// 使用defer确保Rows关闭
defer rows.Close()
for rows.Next() {
// 处理数据
}
// 检查迭代过程中的错误
if err := rows.Err(); err != nil {
return fmt.Errorf("rows iteration error: %w", err)
}
// 显式关闭
rows.Close()
time.Sleep(time.Minute)
}
}
关键点:
- 每次查询后必须调用
Rows.Close() - 使用
defer作为安全网,防止在错误发生时资源泄漏 - 检查查询和迭代过程中的错误
- 考虑使用
QueryContext以便可以取消长时间运行的查询
在你的原始代码中,每次循环都创建新的 Rows 对象但没有关闭之前的,导致游标数量持续增长直到达到数据库限制。

