mirror of https://github.com/sunface/rust-course
parent
2d43a8e4d4
commit
52d0c47375
@ -1 +1,123 @@
|
||||
# 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 数据库
|
||||
|
||||
使用 `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