Пост

Работа с базами данных в Go. Bun ORM

Bun — это высокопроизводительный ORM и SQL-Query builder для Go, построенный поверх pg и полностью совместимый с database/sql. Он поддерживает PostgreSQL, MySQL, MariaDB и SQLite.

Bun ориентирован на производительность, лаконичность и гибкость, предлагая как полноценный ORM, так и возможность писать кастомный SQL.


🔍 Ключевые особенности

  • Совместимость с database/sql
  • 🚀 Высокая производительность (без рефлексии во время выполнения)
  • 🔧 Миграции, ORM, SQL Builder — всё в одном
  • 📦 Удобная работа со связями (has one, has many, many to many)
  • 🧠 Простой синтаксис, без магии
  • 📈 Поддержка soft-delete, hooks, embed’ов, кастомных типов

🧱 Сравнение с другими библиотеками

Критерий Bun GORM Ent SQLX
Поддержка database/sql ✅ Да ❌ Нет (использует собственный драйвер) ✅ Да ✅ Да
Производительность ⚡ Высокая 🐢 Ниже из-за рефлексии ⚡ Очень высокая (генерация кода) ⚡ Высокая (ручной SQL)
Поддержка связей ✅ Есть ✅ Есть ✅ Через edges ❌ Нет
Типобезопасность ⚠️ Частичная (через struct) ❌ Нет ✅ Полная ❌ Нет
Миграции ✅ Встроенные ❌ Внешние библиотеки ✅ Встроенные ❌ Внешние библиотеки
Сложные запросы ✅ SQL Builder ⚠️ ORM + Raw SQL ⚠️ ORM + немного SQL ✅ Только Raw SQL
Удобство ✅ Баланс ORM и SQL ✅ Быстрый старт 📈 Более сложный старт 📉 Только SQL, без ORM

🔨 Примеры использования

1. Инициализация

1
2
3
4
5
6
7
8
import (
    "github.com/uptrace/bun"
    _ "github.com/lib/pq"
    "database/sql"
)

dbSQL, _ := sql.Open("postgres", "postgres://user:pass@localhost:5432/db?sslmode=disable")
db := bun.NewDB(dbSQL, pgdialect.New())

2. Модель

1
2
3
4
5
6
7
8
9
type Example struct {
    bun.BaseModel `bun:"table:examples"`

    ID        int64     `bun:",pk,autoincrement"`
    Hash      string    `bun:",unique,notnull"`
    Filename  string    `bun:",notnull"`
    Source    *string
    CreatedAt time.Time `bun:",nullzero,notnull,default:current_timestamp"`
}

3. Создание таблицы (миграция)

1
2
ctx := context.Background()
err := db.ResetModel(ctx, (*Example)(nil)) // Удаляет и создаёт таблицу

4. Создание записи

1
2
3
4
_, err := db.NewInsert().Model(&Example{
    Hash:     "abc123",
    Filename: "order.xlsx",
}).Exec(ctx)

5. Запрос данных

1
2
3
4
5
var examples []Example
err := db.NewSelect().
    Model(&examples).
    Where("hash = ?", "abc123").
    Scan(ctx)

6. Обновление записи

1
2
3
4
5
_, err := db.NewUpdate().
    Model(&Example{}).
    Set("filename = ?", "order.xlsx").
    Where("hash = ?", "abc123").
    Exec(ctx)

7. Связи между моделями

1
2
3
4
5
type Metadata struct {
    ID       int64  `bun:",pk,autoincrement"`
    ExampleID   int64
    Example  *Example `bun:"rel:belongs-to"`
}

Bun поддерживает:

  • has one
  • has many
  • belongs to
  • many to many

8. Миграции

Bun поставляется с утилитой миграций:

1
2
3
bun migrate init
bun migrate create init_schema
bun migrate up

Файлы миграций — обычные .sql-файлы. Bun сохраняет версию миграций в таблице bun_migrations.


💡 Когда выбирать Bun

Bun хорошо подходит если:

  • Нужен баланс между низкоуровневым контролем и удобством ORM;
  • Нужна производительность, но без необходимости писать весь SQL вручную;
  • Проект использует database/sql и драйверы (pgx, pq, mysql, sqlite и др.);
  • Нужно прозрачное поведение;
  • Нужны удобные миграции и поддержка связей без лишнего веса.

❗ На что обратить внимание

  • Bun не предлагает полную типобезопасность как Ent или sqlc — будьте внимательны к SQL;
  • Некоторые вещи (например, сложные JOIN‘ы) всё равно лучше делать вручную;
  • Нет автоматической генерации GraphQL или OpenAPI.
Больше полезной информации в Telegram-канале