Go: SQL
Теория: Подготовленные выражения
Когда приложение много раз выполняет один и тот же SQL-запрос, меняя только значения параметров, ему не нужно каждый раз проходить полный цикл: отправить текст SQL, дождаться анализа, построения структуры запроса и только потом передать параметры. Вместо этого оно вызывает PrepareContext() — метод, который создаёт объект Stmt.Этот объект представляет подготовленное выражение и позволяет многократно выполнять один и тот же запрос с разными параметрами
В случае использования db.PrepareContext() выражение не закрепляется жёстко за одним соединением: при выполнении драйвер может использовать разные соединения из пула и при необходимости подготавливать выражение на каждом из них отдельно. После подготовки приложение выполняет только подстановку параметров и запуск выражения, как правило, без повторной передачи полного текста SQL при каждом выполнении (конкретное поведение зависит от драйвера). Такой подход особенно удобен в циклах, синхронизациях и любых операциях, где запрос повторяется десятки или сотни раз.
Подготовленное выражение для запросов, которые возвращают строки
Подготовленное выражение можно использовать не только для изменений, но и для запросов, которые возвращают строки. Программа создаёт Stmt один раз, а затем вызывает QueryContext() на том же объекте столько раз, сколько нужно. Каждый вызов открывает новый поток результатов, и приложение считывает строки через Next() и Scan(). Объект Rows удерживает соединение занятым до тех пор, пока не будет вызван rows.Close() или пока не будут прочитаны все строки. Поэтому поток результатов нужно закрывать после каждой выборки, иначе соединения из пула могут временно исчерпаться.
Если закрытие перенести в defer внутри цикла, незакрытые Rows будут накапливаться и удерживать соединения из пула до выхода из функции, а не освобождаться после каждой итерации. Поэтому поток закрывают вручную, сразу после использования, а затем переходят к следующему набору параметров.
Как Stmt взаимодействует с соединениями
Подготовленное выражение, созданное через db.PrepareContext(), является абстракцией на уровне database/sql. Оно может выполняться через разные соединения из пула, и соединение выделяется только на время конкретного вызова ExecContext() или QueryContext(). После завершения операции и закрытия Rows соединение возвращается в пул.
Подготовленные выражения следует закрывать, когда они больше не нужны, чтобы освободить ресурсы на стороне драйвера и сервера базы данных. Однако их можно хранить и переиспользовать длительное время, если один и тот же запрос выполняется часто.
Подготовленное выражение внутри транзакции
Когда программа открывает транзакцию, все операции выполняются через одно соединение, поэтому подготовленное выражение оказывается привязанным к тому же подключению. Такой подход удобен, когда нужно выполнить серию связанных действий: транзакция обеспечивает целостность, а Stmt уменьшает накладные расходы на повторяющийся SQL. Последовательность всегда одна и та же: BeginTx() → PrepareContext() на tx → ExecContext()/QueryContext() → Commit().
Подготовленные выражения, созданные через tx.PrepareContext(), действительны только в рамках данной транзакции и используют то же соединение. После Commit() или Rollback() такое выражение больше нельзя использовать, и его следует закрыть для освобождения связанных ресурсов, потому что соединение транзакции возвращается в пул и её контекст завершён.
Время жизни подготовленного выражения и закрытие ресурсов
Время жизни подготовленного выражения определяется логикой приложения: его используют, пока запрос остаётся востребованным, и закрывают, когда он больше не нужен. Программа открывает Stmt в одном участке кода, использует его для серии операций и затем закрывает через Close(), чтобы освободить ресурсы подготовленного выражения на стороне драйвера и базы данных. Открытый Stmt, созданный через DB, сам по себе не удерживает соединение постоянно. Соединения удерживаются активными объектами Rows во время чтения результатов, а также на время выполнения запросов.
Объект *sql.Stmt безопасен для конкурентного использования несколькими горутинами. Часто используемые подготовленные выражения допускается кэшировать и переиспользовать в разных частях приложения при условии корректного управления их жизненным циклом.


