数据库

创建 sqlite 数据库

rusqlite-badge cat-database-badge

使用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(())
}

插入并查询数据

rusqlite-badge cat-database-badge

Connection::open将打开在早期食谱中,创建的数据库cats。此食谱将数据插入到cat_colors,还有和cats表用到Connectionexecute方法。 首先,将数据插入cat_colors表。插入颜色(color)记录后,Connectionlast_insert_rowid方法,能获取最后插入(color)的id。这个id能用来,把数据插入到cats表。然后,使用prepare方法准备查询,它会返回statement结构。然后,再使用statementquery_map方法(进行查询).

extern crate rusqlite;

use rusqlite::{Connection, Result};
use rusqlite::NO_PARAMS;
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(())
}

使用事务

rusqlite-badge cat-database-badge

Connection::open将打开cats.db —— 来自之前食谱的数据库。

Connection::transaction开始一个事务(transaction)。事务将回滚,除非明确使用Transaction::commit提交。

一次事务,就是一系列对数据库的操作,且明确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()
}