0Pricing
Learn Rust Coding · Урок

Операции CRUD

Запросы и выполнение

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

CRUD с sqlx

CRUD означает Create, Read, Update, Delete: создание, чтение, изменение и удаление. sqlx разделяет их на два способа выполнения:

  • fetch_* — для запросов, возвращающих строки
  • execute — для операторов, изменяющих данные

Создание (INSERT)

Вставьте строку с привязанными параметрами и выполните запрос через execute. Используйте RETURNING, чтобы получить обратно сгенерированный идентификатор.

use sqlx::{Pool, Postgres};

async fn create(pool: &Pool<Postgres>, name: &str) -> i32 {
    let rec = sqlx::query!(
        "INSERT INTO users (name) VALUES ($1) RETURNING id",
        name
    ).fetch_one(pool).await.unwrap();
    rec.id
}

Чтение одной строки

fetch_one ожидает ровно одну строку и сообщает об ошибке в противном случае. Используйте fetch_optional, если строка может отсутствовать.

use sqlx::{Pool, Postgres};

async fn find(pool: &Pool<Postgres>, id: i32) -> Option<String> {
    let rec = sqlx::query!("SELECT name FROM users WHERE id = $1", id)
        .fetch_optional(pool)
        .await
        .unwrap();
    rec.map(|r| r.name)
}

Чтение нескольких строк

fetch_all возвращает Vec всех подходящих строк.

use sqlx::{Pool, Postgres};

async fn all_names(pool: &Pool<Postgres>) -> Vec<String> {
    let rows = sqlx::query!("SELECT name FROM users ORDER BY id")
        .fetch_all(pool)
        .await
        .unwrap();
    rows.into_iter().map(|r| r.name).collect()
}

Изменение

Операторы UPDATE используют execute, который возвращает результат с числом затронутых строк.

use sqlx::{Pool, Postgres};

async fn rename(pool: &Pool<Postgres>, id: i32, name: &str) -> u64 {
    let res = sqlx::query!("UPDATE users SET name = $1 WHERE id = $2", name, id)
        .execute(pool)
        .await
        .unwrap();
    res.rows_affected()
}

Удаление

Для DELETE также используется execute. Вызовите rows_affected(), чтобы узнать, были ли удалены какие-либо данные.

use sqlx::{Pool, Postgres};

async fn delete(pool: &Pool<Postgres>, id: i32) -> bool {
    let res = sqlx::query!("DELETE FROM users WHERE id = $1", id)
        .execute(pool)
        .await
        .unwrap();
    res.rows_affected() > 0
}

Моделирование CRUD в обычном Rust

CRUD в памяти с использованием отображения отражает те же операции, которые sqlx выполняет над таблицей.

use std::collections::HashMap;

fn main() {
    let mut users: HashMap<i32, String> = HashMap::new();
    users.insert(1, "Alice".to_string());      // create
    println!("{:?}", users.get(&1));            // read
    users.insert(1, "Alicia".to_string());      // update
    println!("{:?}", users.get(&1));
    users.remove(&1);                            // delete
    println!("{:?}", users.get(&1));
}

Транзакции

Объединяйте несколько операторов атомарно с помощью транзакции. Либо все они успешно применяются при вызове commit, либо не применяется ни один.

use sqlx::{Pool, Postgres};

async fn transfer(pool: &Pool<Postgres>) {
    let mut tx = pool.begin().await.unwrap();
    sqlx::query!("UPDATE acct SET bal = bal - 10 WHERE id = 1")
        .execute(&mut *tx).await.unwrap();
    sqlx::query!("UPDATE acct SET bal = bal + 10 WHERE id = 2")
        .execute(&mut *tx).await.unwrap();
    tx.commit().await.unwrap();
}

Откат изменений

Если защитный объект транзакции удалён без вызова commit, sqlx автоматически выполняет откат. Также можно явно вызвать rollback.

use sqlx::{Pool, Postgres};

async fn maybe(pool: &Pool<Postgres>, ok: bool) {
    let mut tx = pool.begin().await.unwrap();
    sqlx::query!("INSERT INTO log (msg) VALUES ('x')").execute(&mut *tx).await.unwrap();
    if ok { tx.commit().await.unwrap(); } else { tx.rollback().await.unwrap(); }
}

Потоковая обработка больших выборок

Для огромных наборов результатов fetch возвращает поток, чтобы обрабатывать строки, не загружая их все в память.

use sqlx::{Pool, Postgres};
use futures::TryStreamExt;

async fn stream(pool: &Pool<Postgres>) {
    let mut rows = sqlx::query!("SELECT id FROM big_table").fetch(pool);
    while let Some(row) = rows.try_next().await.unwrap() {
        println!("id {}", row.id);
    }
}

Обработка ошибок

Вызовы базы данных возвращают Result. В функциях, возвращающих Result<_, sqlx::Error>, передавайте ошибки дальше с помощью ?, а не используйте распаковку результата.

use sqlx::{Pool, Postgres};

async fn count(pool: &Pool<Postgres>) -> Result<i64, sqlx::Error> {
    let rec = sqlx::query!("SELECT COUNT(*) as n FROM users")
        .fetch_one(pool)
        .await?;
    Ok(rec.n.unwrap_or(0))
}

Быстрая проверка

Проверьте своё понимание операций CRUD.

Итоги

Вы изучили CRUD с помощью sqlx:

  • fetch_one, fetch_optional, fetch_all считывают строки
  • execute изменяет данные и сообщает значение rows_affected()
  • RETURNING получает сгенерированные значения
  • Транзакции с begin/commit/rollback обеспечивают атомарность

Далее: миграции для развития схемы.

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

Урок «Операции CRUD» бесплатный?

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

Чему я научусь в уроке «Операции CRUD»?

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

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

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

Сколько времени занимает урок «Операции CRUD»?

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

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

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

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

  1. Подключение к базе данных
  2. Запросы с проверкой во время компиляции
  3. Операции CRUD
  4. Миграции
← Назад к Learn Rust Coding