SQLite
Создание базы данных SQLite
Пакет rusqlite
позволяет работать с базами данных SQLite. Посмотрите этот пакет, если вам необходима компиляция под Windows.
Connection::open
создаёт базу данных, если она ещё не существует.
extern crate rusqlite; use rusqlite::{Connection, Result}; use rusqlite::NO_PARAMS; fn main() -> Result<()> { let conn = Connection::open("cats.db")?; conn.execute( "create table if not exists cat_colors ( id integer primary key, name text not null unique )", NO_PARAMS, )?; conn.execute( "create table if not exists cats ( id integer primary key, name text not null, color_id integer not null references cat_colors(id) )", NO_PARAMS, )?; Ok(()) }
Выборка и вставка данных
Connection::open
откроет базу данных cats
, созданную в прошлом рецепте. Этот рецепт создаёт таблицы cat_colors
и cats
с помощью метода execute
из Connection
. Сначала данные вставляются в таблицу cat_colors
. После того как запись о цвете вставилась, метод last_insert_rowid
из Connection
используется для получения id
последней вставленной записи цвета. Этот id
используется при вставке данных в таблицу cats
. Затем подготавливается запрос на выборку с помощью метода prepare
, который возвращает структуру statement
. Затем выполняется запрос, используя метод query_map
из statement
.
extern crate rusqlite; use rusqlite::NO_PARAMS; use rusqlite::{Connection, Result}; use std::collections::HashMap; #[derive(Debug)] struct Cat { name: String, color: String, } fn main() -> Result<()> { let conn = Connection::open("cats.db")?; let mut cat_colors = HashMap::new(); cat_colors.insert(String::from("Blue"), vec!["Tigger", "Sammy"]); cat_colors.insert(String::from("Black"), vec!["Oreo", "Biscuit"]); for (color, catnames) in &cat_colors { conn.execute( "INSERT INTO cat_colors (name) values (?1)", &[&color.to_string()], )?; let last_id: String = conn.last_insert_rowid().to_string(); for cat in catnames { conn.execute( "INSERT INTO cats (name, color_id) values (?1, ?2)", &[&cat.to_string(), &last_id], )?; } } let mut stmt = conn.prepare( "SELECT c.name, cc.name from cats c INNER JOIN cat_colors cc ON cc.id = c.color_id;", )?; let cats = stmt.query_map(NO_PARAMS, |row| { Ok(Cat { name: row.get(0)?, color: row.get(1)?, }) })?; for cat in cats { println!("Found cat {:?}", cat); } Ok(()) }
Использование транзакций
[Connection::open
] откроет базу данных cats.db
из первого рецепта.
Начните транзакцию с помощью Connection::transaction
. Транзакции будут отменены, если они не будут явно закрыты с помощью Transaction::commit
.
В следующем примере цвета добавляются в таблицу, которая имеет ограничение на уникальность для названия цвета. При попытке вставки дублирующего цвета транзакция откатывается.
extern crate rusqlite; use rusqlite::{Connection, Result, NO_PARAMS}; fn main() -> Result<()> { let mut conn = Connection::open("cats.db")?; successful_tx(&mut conn)?; let res = rolled_back_tx(&mut conn); assert!(res.is_err()); Ok(()) } fn successful_tx(conn: &mut Connection) -> Result<()> { let tx = conn.transaction()?; tx.execute("delete from cat_colors", NO_PARAMS)?; tx.execute("insert into cat_colors (name) values (?1)", &[&"lavender"])?; tx.execute("insert into cat_colors (name) values (?1)", &[&"blue"])?; tx.commit() } fn rolled_back_tx(conn: &mut Connection) -> Result<()> { let tx = conn.transaction()?; tx.execute("delete from cat_colors", NO_PARAMS)?; tx.execute("insert into cat_colors (name) values (?1)", &[&"lavender"])?; tx.execute("insert into cat_colors (name) values (?1)", &[&"blue"])?; tx.execute("insert into cat_colors (name) values (?1)", &[&"lavender"])?; tx.commit() }