mirror of https://github.com/sunface/rust-course
parent
2d43a8e4d4
commit
52d0c47375
@ -1 +1,123 @@
|
|||||||
# Postgres
|
# Postgres
|
||||||
|
|
||||||
|
### 在数据库中创建表格
|
||||||
|
我们通过 [postgres](https://docs.rs/postgres/0.17.2/postgres/) 来操作数据库。下面的例子有一个前提:数据库 `library` 已经存在,其中用户名和密码都是 `postgres`。
|
||||||
|
|
||||||
|
```rust,editable
|
||||||
|
use postgres::{Client, NoTls, Error};
|
||||||
|
|
||||||
|
fn main() -> Result<(), Error> {
|
||||||
|
// 连接到数据库 library
|
||||||
|
let mut client = Client::connect("postgresql://postgres:postgres@localhost/library", NoTls)?;
|
||||||
|
|
||||||
|
client.batch_execute("
|
||||||
|
CREATE TABLE IF NOT EXISTS author (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
name VARCHAR NOT NULL,
|
||||||
|
country VARCHAR NOT NULL
|
||||||
|
)
|
||||||
|
")?;
|
||||||
|
|
||||||
|
client.batch_execute("
|
||||||
|
CREATE TABLE IF NOT EXISTS book (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
title VARCHAR NOT NULL,
|
||||||
|
author_id INTEGER NOT NULL REFERENCES author
|
||||||
|
)
|
||||||
|
")?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 插入和查询
|
||||||
|
|
||||||
|
```rust,editable
|
||||||
|
use postgres::{Client, NoTls, Error};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
struct Author {
|
||||||
|
_id: i32,
|
||||||
|
name: String,
|
||||||
|
country: String
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> Result<(), Error> {
|
||||||
|
let mut client = Client::connect("postgresql://postgres:postgres@localhost/library",
|
||||||
|
NoTls)?;
|
||||||
|
|
||||||
|
let mut authors = HashMap::new();
|
||||||
|
authors.insert(String::from("Chinua Achebe"), "Nigeria");
|
||||||
|
authors.insert(String::from("Rabindranath Tagore"), "India");
|
||||||
|
authors.insert(String::from("Anita Nair"), "India");
|
||||||
|
|
||||||
|
for (key, value) in &authors {
|
||||||
|
let author = Author {
|
||||||
|
_id: 0,
|
||||||
|
name: key.to_string(),
|
||||||
|
country: value.to_string()
|
||||||
|
};
|
||||||
|
|
||||||
|
// 插入数据
|
||||||
|
client.execute(
|
||||||
|
"INSERT INTO author (name, country) VALUES ($1, $2)",
|
||||||
|
&[&author.name, &author.country],
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询数据
|
||||||
|
for row in client.query("SELECT id, name, country FROM author", &[])? {
|
||||||
|
let author = Author {
|
||||||
|
_id: row.get(0),
|
||||||
|
name: row.get(1),
|
||||||
|
country: row.get(2),
|
||||||
|
};
|
||||||
|
println!("Author {} is from {}", author.name, author.country);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 聚合数据
|
||||||
|
|
||||||
|
下面代码将使用降序的方式列出 [Museum of Modern Art]() 数据库中的前 7999 名艺术家的国籍分布.
|
||||||
|
|
||||||
|
```rust,editable
|
||||||
|
use postgres::{Client, Error, NoTls};
|
||||||
|
|
||||||
|
struct Nation {
|
||||||
|
nationality: String,
|
||||||
|
count: i64,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> Result<(), Error> {
|
||||||
|
let mut client = Client::connect(
|
||||||
|
"postgresql://postgres:postgres@127.0.0.1/moma",
|
||||||
|
NoTls,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
for row in client.query
|
||||||
|
("SELECT nationality, COUNT(nationality) AS count
|
||||||
|
FROM artists GROUP BY nationality ORDER BY count DESC", &[])? {
|
||||||
|
|
||||||
|
let (nationality, count) : (Option<String>, Option<i64>)
|
||||||
|
= (row.get (0), row.get (1));
|
||||||
|
|
||||||
|
if nationality.is_some () && count.is_some () {
|
||||||
|
|
||||||
|
let nation = Nation{
|
||||||
|
nationality: nationality.unwrap(),
|
||||||
|
count: count.unwrap(),
|
||||||
|
};
|
||||||
|
println!("{} {}", nation.nationality, nation.count);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
@ -1 +1,136 @@
|
|||||||
# SQLite
|
# SQLite
|
||||||
|
|
||||||
|
### 创建 SQLite 数据库
|
||||||
|
|
||||||
|
使用 `rusqlite` 可以创建 SQLite 数据库,[Connection::open](https://docs.rs/rusqlite/*/rusqlite/struct.Connection.html#method.open) 会尝试打开一个数据库,若不存在,则创建新的数据库。
|
||||||
|
|
||||||
|
> 这里创建的 `cats.db` 数据库将被后面的例子所使用
|
||||||
|
|
||||||
|
|
||||||
|
```rust,editable
|
||||||
|
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(())
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 插入和查询
|
||||||
|
|
||||||
|
```rust,editable
|
||||||
|
|
||||||
|
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()],
|
||||||
|
)?;
|
||||||
|
// 获取最近插入数据行的 id
|
||||||
|
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::transaction](https://docs.rs/rusqlite/*/rusqlite/struct.Connection.html#method.transaction) 可以开始新的事务,若没有对事务进行显式地提交 [Transaction::commit](https://docs.rs/rusqlite/0.27.0/rusqlite/struct.Transaction.html#method.commit),则会进行回滚。
|
||||||
|
|
||||||
|
下面的例子中,`rolled_back_tx` 插入了重复的颜色名称,会发生回滚。
|
||||||
|
|
||||||
|
```rust,editable
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
```
|
Loading…
Reference in new issue