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.rsuse 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"