Интеграция с базами данных (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 — локальная установка не требуется.
Все уроки этого курса
- REST API с Actix-web/Rocket
- Интеграция с базами данных (SQLx/Diesel)
- Аутентификация и авторизация