Ответ
При работе с пакетными операциями (например, через pgx.Batch
) критически важно всегда закрывать объект Batch
, чтобы освободить выделенные под него ресурсы как в приложении, так и на стороне сервера базы данных.
Проблема:
Каждый созданный Batch
резервирует соединение из пула и выделяет память. Если не вызвать метод Close()
, эти ресурсы не будут освобождены, что приведёт к утечке соединений и памяти.
Решение:
Используйте defer
для гарантированного вызова batch.Close()
сразу после создания объекта Batch
. Это идиоматический и самый надёжный способ в Go, который сработает даже в случае паники или ошибок.
Пример (с использованием pgx
):
// Предполагается, что 'conn' — это активное соединение с БД
batch := &pgx.Batch{}
// Добавляем операции в пакет
batch.Queue("INSERT INTO users (name) VALUES ($1)", "Alice")
batch.Queue("UPDATE products SET stock = stock - 1 WHERE id = $1", 101)
// Отправляем пакет на выполнение
results := conn.SendBatch(context.Background(), batch)
// ОБЯЗАТЕЛЬНО закрываем ридер результатов, чтобы освободить соединение
defer results.Close()
// Обрабатываем результаты (даже если они не нужны,
// нужно вызвать Close для освобождения ресурсов)
_, err := results.Exec()
if err != nil {
log.Printf("Ошибка выполнения первой операции в пакете: %v", err)
}
_, err = results.Exec()
if err != nil {
log.Printf("Ошибка выполнения второй операции в пакете: %v", err)
}
Ключевой момент: В pgx
версии v4/v5, SendBatch
возвращает BatchResults
, у которого тоже есть метод Close()
. Его обязательно нужно вызывать, чтобы вернуть соединение обратно в пул. Использование defer
— лучший способ это гарантировать.