Гид по технологиям

Использование SQL-баз данных в Go

5 min read Development Обновлено 29 Dec 2025
SQL-базы данных в Go — руководство
SQL-базы данных в Go — руководство

Диаграмма: четыре компонента подключаются к центральному серверу базы данных

Что такое SQL и RDBMS

SQL — это язык запросов для реляционных баз данных (RDBMS). Данные хранятся в таблицах с колонками и строками. Популярные системы: MySQL, PostgreSQL, Microsoft SQL Server и SQLite. Реляционные БД хорошо подходят для согласованных транзакционных данных, сложных связей и аналитики.

Краткое определение: RDBMS — система управления базами данных, где данные организованы в таблицы и поддерживаются связи между ними.

Пакет database/sql в Go

В Go функциональность для работы с SQL расположена в пакете database/sql. Это абстрактный интерфейс. Он не знает конкретных особенностей СУБД. Чтобы подключиться к настоящему серверу, нужен драйвер — отдельный пакет, реализующий конкретную СУБД.

Важно: вы используете database/sql одинаково для разных СУБД, а различия (формат строки подключения, поддерживаемые типы и расширенные возможности) обрабатывает драйвер.

Популярные драйверы Go

  • Go-SQL Driver — MySQL (github.com/go-sql-driver/mysql)
  • PQ — PostgreSQL (github.com/lib/pq) (часто сокращают как pq)
  • Go-SQLite3 — SQLite (github.com/mattn/go-sqlite3)
  • MSSQL DB — Microsoft SQL Server (github.com/denisenkom/go-mssqldb)

Полезный ресурс для поиска драйверов: LibHunt и списки пакетов в GitHub. Они помогают подобрать драйвер по популярности и совместимости.

Обзорный ресурс по драйверам баз данных для Go

Установка и импорт драйвера

После инициализации модуля (go mod init) установите драйвер для вашей СУБД. Примеры для MySQL и SQLite:

# Установка драйверов
go get -u github.com/go-sql-driver/mysql
go get github.com/mattn/go-sqlite3

Затем импортируйте драйвер ради побочного эффекта, чтобы он зарегистрировал себя в database/sql:

import (
    "database/sql"
    _ "github.com/go-sql-driver/mysql"
)

Импорт с подчеркиванием (_) нужен, когда вы не обращаетесь к пакету напрямую, но драйвер должен выполнить инициализацию (регистрацию).

Важно: для некоторых драйверов (например, mattn/go-sqlite3) требуется CGO. На некоторых CI/сборках это нужно учесть.

Подключение к базе данных

Создайте подключение через sql.Open(driverName, dataSourceName). Open возвращает *sql.DB — пул соединений, а не одно сетевое соединение.

// SQLite
db, err := sql.Open("sqlite3", "models/testdb.db")
if err != nil {
    log.Fatalln(err)
}

// MySQL
db, err := sql.Open("mysql", "user:password@/dbname")
if err != nil {
    log.Fatalln(err)
}

После sql.Open рекомендуется вызвать db.Ping() или db.PingContext(ctx) для проверки доступности БД.

if err := db.Ping(); err != nil {
    log.Fatalln("database unreachable:", err)
}

Характерная модель: *sql.DB управляет пулом. Вы вызываете db.Close() при завершении программы.

Подготовка и выполнение SQL-команд

Для повторяющихся или параметризованных запросов используют подготовленные выражения (Prepare) или Exec/Query с аргументами.

command, err := db.Prepare("CREATE TABLE IF NOT EXISTS login(username TEXT, password TEXT)")
if err != nil {
    log.Fatalln(err)
}
_, err = command.Exec()
if err != nil {
    log.Fatalln(err)
}

Пример вставки с плейсхолдерами ? (синтаксис ? применим не ко всем драйверам — PostgreSQL использует $1, $2):

command, err := db.Prepare("INSERT INTO login(username, password) values(?,?)")
if err != nil {
    log.Fatalln(err)
}
exec, err := command.Exec("alice", "s3cret")
if err != nil {
    log.Fatalln(err)
}

affected, err := exec.RowsAffected()
if err != nil {
    log.Fatalln(err)
}
fmt.Println("Rows affected:", affected)

id, err := exec.LastInsertId()
if err == nil {
    fmt.Println("Last insert ID:", id)
}

Совет: при использовании PostgreSQL вместо ? применяйте нумерованные параметры $1, $2.

Получение результатов запросов

Для чтения наборов строк используйте Query и итерируйте с rows.Next():

rows, err := db.Query("SELECT username, password FROM login")
if err != nil {
    log.Fatalln(err)
}
defer rows.Close()

var username, password string
for rows.Next() {
    if err := rows.Scan(&username, &password); err != nil {
        log.Fatalln(err)
    }
    fmt.Println(username, password)
}

if err := rows.Err(); err != nil {
    log.Fatalln(err)
}

Scan копирует значения текущей строки в переданные переменные. Типы должны соответствовать типам столбцов или быть совместимы.

Практические рекомендации и эвристики

  • Всегда закрывайте rows и stmt через defer сразу после успешного создания.
  • Используйте контексты (context.Context) для таймаутов и отмен.
  • Проверяйте ошибки после итерации rows через rows.Err().
  • Не храните секреты (пароли, DSN) в коде — используйте переменные окружения или секретные хранилища.
  • Настраивайте параметры пула: db.SetMaxOpenConns, db.SetMaxIdleConns, db.SetConnMaxLifetime.

Ментальная модель: *sql.DB — это пул, sql.Conn — конкретное соединение, sql.Tx — транзакция, sql.Stmt — подготовленное выражение.

Когда реляционная база не подходит

Контрпримеры/когдa стоит искать альтернативу:

  • Очень гибкая схема данных с частыми изменениями структуры — рассмотрите документоориентированные БД (NoSQL).
  • Требуются сверхнизкие задержки записи больших потоков — возможно, лог-ориентированные хранилища или специализированные очереди.
  • Для простых однопользовательских CLI-инструментов SQLite хороша, но для многопользовательских нагрузок — лучше серверная СУБД.

Альтернативные подходы

  • ORM: GORM, Ent, sqlc. Они упрощают работу с моделями, миграциями и выборками, но вводят слой абстракции.
  • sqlx: расширяет database/sql удобными хелперами (Get, Select) без полной ORM.
  • NoSQL: MongoDB, Redis — для нереляционных задач.

Выбор: если важна прозрачность SQL и контроль — используйте database/sql/sqlx. Если хотите быстрее разработать CRUD и готовы к абстракциям — ORM.

Роли и чеклисты

Разработчику:

  • Установить и импортировать правильный драйвер.
  • Настроить db.Ping() и таймауты.
  • Использовать подготовленные выражения для пользовательских вводов.
  • Закрывать rows и stmt.
  • Логировать и обрабатывать ошибки.

DBA / инфраструктуре:

  • Обеспечить отказоустойчивость СУБД и резервные копии.
  • Настроить учётные записи с минимальными привилегиями.
  • Мониторить метрики пула соединений и задержки.

Безопасность и харднинг

  • Параметризуйте запросы, чтобы избежать SQL-инъекций.
  • Ограничьте права пользователя БД только необходимыми привилегиями.
  • Шифруйте трафик между приложением и БД (TLS).
  • Храните секреты в менеджере секретов (Vault, AWS Secrets Manager) или переменных окружения, но не в репозиториях.
  • Проводите аудит и логи запросов при необходимости.

Критерии приёмки

  • Приложение успешно подключается к БД и проходит db.Ping().
  • Запросы возвращают ожидаемые данные, а rows.Err() не содержит ошибок.
  • Все ресурсы (rows, stmt, db) корректно закрываются.
  • Пароли и DSN не хранятся в кодовой базе в открытом виде.

Шпаргалка: шаблоны и строки подключения

  • SQLite: sql.Open("sqlite3", "path/to/file.db")
  • MySQL: sql.Open("mysql", "user:password@tcp(127.0.0.1:3306)/dbname?parseTime=true")
  • PostgreSQL: sql.Open("postgres", "postgres://user:pass@localhost/dbname?sslmode=disable") (или используя $1 параметры)

Пример с контекстом и таймаутом:

ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

if err := db.PingContext(ctx); err != nil {
    return err
}

Тесты и приёмо-сдаточные случаи

  • Интеграционный тест: поднять контейнер с той же СУБД и прогнать сценарии вставки/чтения/удаления.
  • Тест отказа: что происходит, если БД недоступна (проверка экспоненциального бэкоффа/поведения приложения).
  • Тест на утечку соединений: проверить, что число открытых соединений стабильно.

Короткая сводка

Используйте database/sql как основной абстрактный уровень. Выбирайте драйвер по СУБД, учитывайте синтаксис параметров и особенности драйвера. Применяйте контексты, параметризованные запросы и настройки пула для надёжности и производительности.

Глоссарий в одну строку

  • DSN: строка подключения к базе данных.
  • Пул соединений: механизм повторного использования сетевых соединений.
  • Prepared statement: подготовленное выражение для повторного выполнения с параметрами.

Краткое резюме:

  • database/sql — интерфейс. Драйверы — реализация.
  • Перед запуском проверяйте db.Ping().
  • Используйте параметры запросов и закрывайте ресурсы.
Поделиться: X/Twitter Facebook LinkedIn Telegram
Автор
Редакция

Похожие материалы

Менеджер неактивного аккаунта Google: настройка и выбор
Приватность и безопасность

Менеджер неактивного аккаунта Google: настройка и выбор

Исправление переэкспозиции в Photoshop
Фотография

Исправление переэкспозиции в Photoshop

Как сохранять места в Google Maps
Навигация

Как сохранять места в Google Maps

Создание уровней в Godot — руководство
Геймдев

Создание уровней в Godot — руководство

Конвертация PDF в PowerPoint — пошагово
Руководство

Конвертация PDF в PowerPoint — пошагово

Snapchat: удалить и понять лучших друзей
Социальные сети

Snapchat: удалить и понять лучших друзей