Работа с PostgreSQL в языке Go
Оглавление
- Синтаксис и категории команд SQL
- Ограничения (Constraints)
- Подходы к работе с БД в Go
- Драйверы для PostgreSQL
- Запуск и миграции
- Практическая работа с pgx
- Методы написания SQL-запросов
1. Синтаксис и категории команд SQL
SQL (Structured Query Language) подразделяется на несколько функциональных групп:
DDL (Data Definition Language) — Определение данных
Команды для управления структурой (схемой) объектов базы данных.
CREATE: Создание новых объектов (таблиц, представлений, индексов).ALTER: Модификация существующих объектов (изменение типов столбцов, добавление полей).DROP: Удаление объектов.
DML (Data Manipulation Language) — Манипуляция данными
Команды для работы с содержимым таблиц.
SELECT: Извлечение (чтение) записей.INSERT: Создание новых записей.UPDATE: Модификация существующих записей.DELETE: Удаление записей.
DCL (Data Control Language) — Управление доступом
Команды для управления правами и безопасностью.
GRANT: Предоставление пользователю определенных прав.REVOKE: Отзыв ранее выданных прав.
TCL (Transaction Control Language) — Управление транзакциями
Команды для обеспечения свойств ACID (атомарности и надежности).
BEGIN: Инициализация транзакции.COMMIT: Фиксация изменений в базе данных.ROLLBACK: Откат изменений к исходному состоянию при ошибке.
2. Ограничения (Constraints)
Правила целостности, обеспечивающие корректность данных (Consistency) на уровне схемы:
- NOT NULL: Запрещает сохранение пустого значения в столбце.
- UNIQUE: Обеспечивает уникальность значений во всех строках столбца.
- PRIMARY KEY: Уникальный идентификатор строки (автоматически включает
UNIQUEиNOT NULL). - FOREIGN KEY: Ссылочная целостность (связывает столбец с первичным ключом другой таблицы).
- CHECK: Проверка значений на соответствие заданному логическому условию.
- EXCLUDE: Ограничение-исключение для предотвращения пересекающихся данных.
3. Подходы к работе с БД в Go
Общий интерфейс database/sql
- Суть: Стандартный пакет Go, задающий универсальный контракт для работы с SQL.
- Механизм регистрации: Драйверы регистрируются через функцию
init(). Используется “пустой” импорт:import _ "github.com/lib/pq". - Использование: Приложение работает через
sql.Open("driverName", "DSN")и стандартные методыdb.Query,db.Exec. Это обеспечивает независимость кода от конкретной реализации СУБД. - Пул соединений: Пакет содержит встроенную структуру
DB, которая автоматически управляет пулом соединений (создание, переиспользование, закрытие).
Кастомные драйверы
- Суть: Библиотеки, не использующие интерфейс
database/sql. - Преимущества: Предоставляют доступ к специфическим функциям СУБД (например, асинхронность в Postgres) и могут быть производительнее.
- Пример:
clientv3для хранилищаetcd.
4. Драйверы для PostgreSQL
lib/pq:- Реализует подход
database/sql. - Полностью нативный (Go).
- Статус: Устарел (Maintenance Mode). Не рекомендуется для новых систем.
- Реализует подход
pgx:- Современный и активно развивающийся драйвер.
- Версии:
pgx/v4,pgx/v5(актуальные). - Особенности: Может работать как через интерфейс
database/sql(через адаптер), так и через собственный расширенный интерфейс. Рекомендуемый выбор.
5. Запуск и миграции
Способы запуска СУБД
- Локально: Установка в ОС (
brew,apt). Удобно для тестов, данные сохраняются. - Docker (Контейнер): Изолированное окружение, легкое управление версиями. Требует настройки
volumesдля сохранения данных и использования инструментов миграций. - Внешний инстанс: Облачные решения или корпоративные БД.
Автоматизация изменений (Migrations as Code)
Использование SQL-скриптов вручную не рекомендуется из-за риска ошибок.
- Инструмент
goose:- Поддерживает двунаправленность (
Up— накат,Down— откат). - Хранит состояние примененных миграций непосредственно в БД.
- Каждая миграция по умолчанию выполняется в транзакции (TCL).
- Поддерживает двунаправленность (
- Лучшие практики миграций:
- Минимальная логика в одном файле.
- Осмысленные имена.
- Обратная совместимость: Изменения не должны ломать работу старых версий приложения (актуально для постепенного обновления/канареечных выкаток).
6. Практическая работа с pgx
Подключение и контекст
pgx.Connect(ctx, "DSN"): Одиночное соединение.- DSN (Data Source Name): Формат
postgres://user:password@host:port/dbname. - Правила:
- Всегда использовать
contextдля контроля таймаутов. - Всегда закрывать соединение через
defer conn.Close(ctx).
- Всегда использовать
Пул соединений (pgxpool)
В нагруженных приложениях вместо одиночных коннектов используется пул:
pgxpool.New(ctx, "DSN"): Создание пула.- Настройки (лимиты, таймауты) передаются через параметры в DSN-строке.
Выполнение запросов
- Одна строка:
db.QueryRow(...).Scan(&var). - Множество строк:
db.Query(...)возвращает итераторRows. Необходимо обходить его в цикле и вызыватьrows.Scan(). - Библиотека
scany: Позволяет автоматически маппить (заполнять) структуры Go данными из БД, сокращая объем шаблонного кода.
7. Методы написания SQL-запросов
| Подход | Инструменты | Плюсы | Минусы |
|---|---|---|---|
| Raw SQL | pgx, database/sql |
Гибкость, прозрачность, макс. скорость. | Много boilerplate-кода, нет проверки типов при компиляции. |
| Query Builder | squirrel |
Защита от инъекций, динамические запросы. | Доп. слой абстракции. |
| ORM | GORM |
Высокая скорость разработки. | Низкая производительность, неявный SQL (риск неэффективных запросов). |
| Codegen | sqlc |
Типобезопасность, скорость Raw SQL. | Сложность с динамическими запросами. |
Резюме по Codegen (sqlc)
Принцип: Разработчик пишет чистый SQL, а утилита генерирует строго типизированный Go-код для выполнения этих запросов. Сочетает производительность Raw SQL и удобство типизации.