Ответ
В Go работа с базами данных построена на основе стандартного пакета database/sql
, который изначально спроектирован для конкурентного использования. Разделение на "синхронный" и "асинхронный" режимы — это скорее вопрос организации вызывающего кода.
1. "Синхронный" подход (блокирующий вызов)
Это наиболее распространенный способ. Вызов функции, например db.QueryContext()
, блокирует текущую горутину до получения ответа от БД. При этом Go runtime эффективно управляет потоками ОС, поэтому блокировка одной горутины не блокирует выполнение всей программы.
// Горутина будет ждать здесь, пока запрос не выполнится
rows, err := db.QueryContext(ctx, "SELECT id, name FROM users WHERE id = ?", 1)
if err != nil {
// Обработка ошибки
}
defer rows.Close()
// ... дальнейшая обработка результата
2. "Асинхронный" подход (неблокирующий вызов)
Достигается путем запуска операции с БД в отдельной горутине. Это позволяет основному потоку выполнения продолжать работу, не дожидаясь завершения запроса к БД. Результат обычно передается через каналы.
ch := make(chan *sql.Rows)
go func() {
defer close(ch)
rows, err := db.QueryContext(ctx, "SELECT * FROM users")
if err != nil {
// Ошибку лучше передавать через отдельный канал или структуру
ch <- nil
return
}
ch <- rows
}()
// Основная горутина может делать другую работу
// ... а затем дождаться результата
resultRows := <-ch
if resultRows != nil {
defer resultRows.Close()
// Обработка результата
}
Ключевые особенности и лучшие практики:
- Пул соединений (Connection Pool): Пакет
database/sql
автоматически управляет пулом соединений. Это ключевой механизм для высокой производительности. Важно настраивать его с помощьюdb.SetMaxOpenConns()
иdb.SetMaxIdleConns()
. - Конкурентность: Объект
*sql.DB
является потокобезопасным и предназначен для долгой жизни и совместного использования в разных горутинах. context.Context
: Всегда используйте версии методов сContext
(например,QueryContext
,ExecContext
). Это позволяет управлять таймаутами, отменой запросов и передавать сквозные данные (tracing).- Библиотеки-обертки: Такие библиотеки, как
sqlx
илиpgx
, упрощают сканирование результатов в структуры, а ORM, какGORM
, абстрагируют SQL-запросы, но все они работают поверхdatabase/sql
.