ORM для Rust: полное сравнение и примеры использования
Экосистема Rust предлагает несколько мощных решений для работы с базами данных. В этой статье мы подробно сравним три основных подхода: Diesel (синхронный, компилируемый ORM), SeaORM (асинхронный, гибкий) и SQLx (минималистичный, с проверкой запросов на этапе компиляции). Вы узнаете, какой инструмент выбрать под конкретные задачи, и увидите рабочие примеры кода.
1. Diesel — проверенный синхронный ORM
Diesel — это самый зрелый ORM для Rust. Его главная фишка — безопасность типов на этапе компиляции. Все SQL-запросы проверяются во время сборки, что исключает целый класс ошибок. Работает только синхронно, но с tokio можно организовать пул соединений.
Пример использования Diesel:
// models.rs
#[derive(Queryable, Insertable)]
#[table_name = "users"]
pub struct User {
pub id: i32,
pub name: String,
pub email: String,
}
// main.rs
use diesel::prelude::*;
use diesel::dsl::insert_into;
fn main() {
let conn = PgConnection::establish("postgres://user:pass@localhost/db")
.expect("Database connection failed");
let new_user = User {
id: 0,
name: "Alice".into(),
email: "alice@example.com".into(),
};
let inserted = insert_into(users::table)
.values(&new_user)
.get_result::<User>(&conn)
.expect("Insert failed");
println!("Created user: {}", inserted.name);
}
Плюсы: максимальная производительность, строгая типизация, встроенные миграции.
Минусы: синхронный, сложная настройка, не поддерживает async из коробки.
2. SeaORM — асинхронный и гибкий
SeaORM — это современный асинхронный ORM, построенный на sqlx. Поддерживает tokio и async-std. Предлагает богатый API для CRUD, отношений (один-к-одному, один-ко-многим) и миграций. Идеален для веб-приложений на Actix или Axum.
Пример с SeaORM:
use sea_orm::*;
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
#[sea_orm(table_name = "users")]
pub struct Model {
#[sea_orm(primary_key)]
pub id: i32,
pub name: String,
pub email: String,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {}
impl ActiveModelBehavior for ActiveModel {}
// Использование
async fn create_user(db: &DatabaseConnection) -> Result<(), DbErr> {
let user = ActiveModel {
name: Set("Bob".to_owned()),
email: Set("bob@example.com".to_owned()),
..Default::default()
};
let result = user.insert(db).await?;
println!("User created with id: {}", result.id);
Ok(())
}
Плюсы: полноценный async, поддержка PostgreSQL, MySQL, SQLite, простые миграции.
Минусы: медленнее Diesel на синтетических тестах, больше зависимостей.
3. SQLx — легковесный и безопасный
SQLx — это не ORM в классическом смысле, а асинхронный SQL-драйвер с проверкой запросов на этапе компиляции. Вы пишете чистый SQL, а SQLx проверяет его синтаксис и типы аргументов. Поддерживает PostgreSQL, MySQL, SQLite. Отличный выбор, если вы предпочитаете полный контроль над запросами.
Пример SQLx:
use sqlx::postgres::PgPool;
#[derive(sqlx::FromRow)]
struct User {
id: i32,
name: String,
email: String,
}
#[tokio::main]
async fn main() -> Result<(), sqlx::Error> {
let pool = PgPool::connect("postgres://user:pass@localhost/db").await?;
let user = sqlx::query_as::<_, User>(
"SELECT id, name, email FROM users WHERE email = $1"
)
.bind("charlie@example.com")
.fetch_one(&pool)
.await?;
println!("Found user: {}", user.name);
Ok(())
}
Плюсы: минимальный overhead, проверка SQL в compile time, async, поддержка миграций.
Минусы: нет автоматической генерации запросов, нужно писать SQL вручную.
4. Сравнительная таблица
- Diesel: Синхронный, строгая типизация, максимальная скорость. Для консольных утилит и высоконагружен
Также в библиотеке
Rate Limiting в PHP: полное руководство по ограничению запросов
Prometheus метрики в Rust: библиотека prometheus и metrics-exporter-prometheus
Интернационализация (i18n) в PHP: библиотека gettext и современные подходы
Конфигурация приложений C# (.NET): Microsoft.Extensions.Configuration
Paging 3 для Kotlin: полное руководство с примерами