0Pricing
Learn Rust Coding · Урок

Интеграция с базами данных (SQLx/Diesel)

Интегрируйте веб-сервис на Rust с базами данных с помощью популярных ORM или конструкторов запросов, таких как SQLx или Diesel.

«Интеграция с базами данных (SQLx/Diesel)» — бесплатный урок Learn Rust Coding на CoddyKit. Это урок 2 из 3. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Learn Rust Coding, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Learn Rust Coding содержит 3 уроков всего.

Зачем нужны базы данных в веб-разработке?

Веб-сервисам часто требуется постоянно хранить и получать данные. Например, профили пользователей, каталоги товаров или записи в блоге — эти данные должны находиться где-то за пределами памяти программы.

Базы данных предоставляют структурированный способ управления такими данными, обеспечивая их безопасность, согласованность и доступность. Интеграция веб-сервиса на Rust с базой данных — одна из основных задач большинства реальных приложений.

SQLx: Ваш помощник для асинхронных баз данных

В Rust есть отличные инструменты для взаимодействия с базами данных. Два популярных варианта — SQLx и Diesel.

  • SQLx: Асинхронный пакет SQL, полностью написанный на Rust, с проверкой запросов во время компиляции. Его часто выбирают для асинхронных веб-сервисов на фреймворках вроде Tokio.
  • Diesel: Мощный ORM (объектно-реляционный преобразователь), предоставляющий более абстрактный способ взаимодействия с базой данных и напрямую сопоставляющий структуры Rust с таблицами базы данных. Обычно он работает синхронно.

В этом уроке мы сосредоточимся на SQLx благодаря его развитой поддержке асинхронности, которая хорошо соответствует современному подходу к разработке веб-сервисов на Rust.

Настройка SQLx: зависимости

До написания кода добавьте sqlx и tokio в файл Cargo.toml проекта. tokio предоставляет асинхронную среду выполнения, необходимую для sqlx.

Например, для использования SQLite (удобной файловой базы данных для локальной разработки) с SQLx файл Cargo.toml может выглядеть так:

[dependencies] sqlx = { version = "0.7", features = ["runtime-tokio-rustls", "sqlite"] } tokio = { version = "1", features = ["full"] }

Обычно также используется переменная окружения DATABASE_URL для настройки строки подключения к базе данных.

Подключение к первой базе данных

Установим соединение с базой данных SQLite, расположенной в памяти. SQLx использует пулы соединений, которые эффективно управляют несколькими соединениями с базой данных для обработки одновременных запросов в веб-сервисе.

Попробуйте запустить этот пример:

use sqlx::SqlitePool;
use tokio;

#[tokio::main]
async fn main() -> Result<(), sqlx::Error> {
    // Use an in-memory SQLite database for simplicity
    let database_url = "sqlite::memory:"; 
    let pool = SqlitePool::connect(&database_url).await?;
    println!("Successfully connected to the database!");

    // In a real web app, 'pool' would be passed around or stored in app state.

    Ok(())
}

Организация данных с помощью таблиц

Прежде чем сохранять данные, необходимо определить схему базы данных с помощью DDL (языка определения данных). Создадим простую таблицу tasks.

Макрос sqlx::query! позволяет встраивать SQL непосредственно в код Rust. Он даже выполняет проверки SQL во время компиляции!

use sqlx::{SqlitePool, query};
use tokio;

#[tokio::main]
async fn main() -> Result<(), sqlx::Error> {
    let database_url = "sqlite::memory:";
    let pool = SqlitePool::connect(&database_url).await?;

    // Create a 'tasks' table if it doesn't exist
    query!(
        "CREATE TABLE IF NOT EXISTS tasks (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            description TEXT NOT NULL,
            completed BOOLEAN NOT NULL DEFAULT FALSE
        )"
    ).execute(&pool).await?;

    println!("Table 'tasks' created successfully!");
    Ok(())
}

Добавление новых записей

Теперь у нас есть таблица — добавим данные! Мы воспользуемся оператором INSERT с привязкой параметров. Это защищает от внедрения SQL-кода и делает запросы безопаснее.

Обратите внимание: для параметров используются заполнители ?, а значения передаются в .bind().

use sqlx::{SqlitePool, query};
use tokio;

#[tokio::main]
async fn main() -> Result<(), sqlx::Error> {
    let database_url = "sqlite::memory:";
    let pool = SqlitePool::connect(&database_url).await?;

    query!(
        "CREATE TABLE IF NOT EXISTS tasks (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            description TEXT NOT NULL,
            completed BOOLEAN NOT NULL DEFAULT FALSE
        )"
    ).execute(&pool).await?;

    // Insert a new task
    let description = "Learn SQLx";
    let completed = false;
    query!(
        "INSERT INTO tasks (description, completed) VALUES (?, ?)",
        description,
        completed
    ).execute(&pool).await?;

    println!("Task '{}' inserted successfully!", description);
    Ok(())
}

Получение данных с помощью SELECT

Чтобы получить данные из таблицы tasks, используется оператор SELECT. SQLx предоставляет методы, такие как .fetch_all() и .fetch_one(), для получения результатов.

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

use sqlx::{SqlitePool, query};
use tokio;

#[tokio::main]
async fn main() -> Result<(), sqlx::Error> {
    let database_url = "sqlite::memory:";
    let pool = SqlitePool::connect(&database_url).await?;

    query!(
        "CREATE TABLE IF NOT EXISTS tasks (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            description TEXT NOT NULL,
            completed BOOLEAN NOT NULL DEFAULT FALSE
        )"
    ).execute(&pool).await?;

    query!(
        "INSERT INTO tasks (description, completed) VALUES (?, ?)",
        "Learn SQLx", false
    ).execute(&pool).await?;
    query!(
        "INSERT INTO tasks (description, completed) VALUES (?, ?)",
        "Build a web app", false
    ).execute(&pool).await?;

    // Fetch and print all tasks
    println!("\n--- All Tasks ---");
    let rows = query!("SELECT id, description, completed FROM tasks")
        .fetch_all(&pool).await?;

    for row in rows {
        println!("ID: {}, Desc: {}, Done: {}", 
            row.id, row.description, row.completed);
    }
    Ok(())
}

Типобезопасные данные со структурами

Извлечение данных из строк вручную может приводить к ошибкам. Макрос query_as! SQLx в сочетании с #[derive(FromRow)] позволяет напрямую сопоставлять результаты запроса со структурами Rust!

Это обеспечивает строгую типобезопасность и делает код намного чище и удобнее.

use sqlx::{FromRow, SqlitePool, query, query_as};
use tokio;

#[derive(Debug, FromRow)]
struct Task {
    id: i64,
    description: String,
    completed: bool,
}

#[tokio::main]
async fn main() -> Result<(), sqlx::Error> {
    let database_url = "sqlite::memory:";
    let pool = SqlitePool::connect(&database_url).await?;

    query!(
        "CREATE TABLE IF NOT EXISTS tasks (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            description TEXT NOT NULL,
            completed BOOLEAN NOT NULL DEFAULT FALSE
        )"
    ).execute(&pool).await?;

    query!(
        "INSERT INTO tasks (description, completed) VALUES (?, ?)",
        "Learn SQLx", false
    ).execute(&pool).await?;

    // Fetch tasks directly into our Task struct
    println!("\n--- Tasks as Structs ---");
    let tasks = query_as::<_, Task>("SELECT id, description, completed FROM tasks")
        .fetch_all(&pool).await?;

    for task in tasks {
        println!("{:?}", task);
    }
    Ok(())
}

Изменение и удаление записей

Обновление и удаление данных выполняется примерно так же, как и вставка. Используются операторы SQL UPDATE и DELETE с привязкой параметров.

  • UPDATE: Изменяет существующие строки на основе условия WHERE.
  • DELETE: Удаляет строки на основе условия WHERE.

Всегда внимательно проверяйте условия WHERE в операторах UPDATE и DELETE, чтобы избежать непреднамеренной потери данных!

use sqlx::{SqlitePool, query};
use tokio;

#[tokio::main]
async fn main() -> Result<(), sqlx::Error> {
    let database_url = "sqlite::memory:";
    let pool = SqlitePool::connect(&database_url).await?;

    query!(
        "CREATE TABLE IF NOT EXISTS tasks (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            description TEXT NOT NULL,
            completed BOOLEAN NOT NULL DEFAULT FALSE
        )"
    ).execute(&pool).await?;

    query!(
        "INSERT INTO tasks (description, completed) VALUES (?, ?)",
        "Finish lesson", false
    ).execute(&pool).await?;
    let task_id_to_update = 1;

    // Update a task
    query!(
        "UPDATE tasks SET completed = ? WHERE id = ?",
        true,
        task_id_to_update
    ).execute(&pool).await?;
    println!("Task {} updated.", task_id_to_update);

    // Delete a task (uncomment to run, careful with IDs after update)
    // let task_id_to_delete = 1;
    // query!(
    //     "DELETE FROM tasks WHERE id = ?",
    //     task_id_to_delete
    // ).execute(&pool).await?;
    // println!("Task {} deleted.", task_id_to_delete);

    Ok(())
}

Проверьте знания о базах данных

Какие из следующих утверждений о SQLx в веб-сервисах на Rust верны?

Интеграция с базой данных: главное

Вы сделали важный шаг к созданию надёжных веб-сервисов на Rust, изучив интеграцию с базами данных!

  • Сохранность данных: Базы данных необходимы для хранения данных приложения.
  • SQLx: Асинхронный пакет SQL с проверкой во время компиляции, отлично подходящий для веб-сервисов.
  • Пулы соединений: Необходимы для эффективного одновременного доступа к базе данных.
  • CRUD: Мы рассмотрели создание (INSERT), получение (SELECT), обновление (UPDATE) и удаление (DELETE) данных.
  • Типобезопасность: query_as! и #[derive(FromRow)] обеспечивают безопасное и удобное сопоставление данных.

Далее Вы можете изучить интеграцию этих операций с базой данных в настоящие веб-маршруты!

Часто задаваемые вопросы

Урок «Интеграция с базами данных (SQLx/Diesel)» бесплатный?

Да — полный текст урока «Интеграция с базами данных (SQLx/Diesel)» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Learn Rust Coding, подпишись на CoddyKit PRO. Курс Learn Rust Coding содержит 3 уроков всего.

Чему я научусь в уроке «Интеграция с базами данных (SQLx/Diesel)»?

Интегрируйте веб-сервис на Rust с базами данных с помощью популярных ORM или конструкторов запросов, таких как SQLx или Diesel. Ты практикуешь Learn Rust Coding с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать Learn Rust Coding?

Предыдущий опыт не требуется. Learn Rust Coding на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 2 из 3.

Сколько времени занимает урок «Интеграция с базами данных (SQLx/Diesel)»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке Learn Rust Coding?

Да. Каждый урок Learn Rust Coding включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. REST API с Actix-web/Rocket
  2. Интеграция с базами данных (SQLx/Diesel)
  3. Аутентификация и авторизация
← Назад к Learn Rust Coding