sqlx 是 rust 的数据库访问工具, 本身并不是 orm,但常见的 orm 都是基于它实现的。其有如下特点:
- 支持异步,适合高并发
- 编译时检查:cargo build 时检查执行 sql,校验响应值
- 支持多数据库:mysql、pg、sqlite 等
- 支持主流 rust 运行时:tokio、async-std、actix、native-tls、rustls等
- 内置连接池
一、数据库、依赖、环境变量
本文操作 pg,首先建表
DROP TABLE IF EXISTS course;
CREATE TABLE course (
id INT8 NOT NULL,
teacher_id INT4 NOT NULL,
name VARCHAR(255) NOT NULL,
time DATE DEFAULT NOW()
);
INSERT INTO course VALUES (1, 11, 'cml', '2022-03-25');
INSERT INTO course VALUES (2, 22, 'cc', '2022-03-25');
INSERT INTO course VALUES (3, 33, 'mm', '2022-03-25');
ALTER TABLE course ADD CONSTRAINT course_pkey PRIMARY KEY (id);
用 cargo new 新建项目,添加依赖:
cargo add sqlx -F postgres -F runtime-tokio-rustls -F macros -F chrono
cargo add dotenv # 环境变量工具。本例中将使用此工具处理数据库连接字符串。
cargo add chrono -F serde # 时间工具
cargo add serde -F derive # 序列化
cargo add actix-web # actix 运行时
cargo add actix-rt # actix 运行时
环境变量
数据库地址可以放在配置文件里,例如在根目录新建一个 .env 文件,内容如下:
DATABASE_URL=postgres://cml:123456@192.168.1.239:5432/postgres
二、增删改查
2.1 完整示例
- dotenv().ok():在访问环境变量之前检查一下,防止因读取环境变量失败导致程序 panic。
- env::var(“DATABASE_URL”):读取环境变量文件中的数据库连接字符串
- PgPoolOptions::new().connect():实例化一个数据库连接池
- sqlx::query!(“sql”) .fetch_all(&pool):执行sql语句
工程目录结构:
│ .env
│ Cargo.toml
├─src
│ main.rs
示例代码:
use chrono::NaiveDate;
use dotenv::dotenv;
use sqlx::postgres::PgPoolOptions;
use std::env;
#[derive(Debug)]
pub struct Course {
pub id: i64,
pub teacher_id: i32,
pub name: String,
pub time: Option<NaiveDate>,
}
#[actix_rt::main]
async fn main() -> Result<(), sqlx::Error> {
println!("Hello, world!");
dotenv().ok();
读取所有的环境变量
// for (key, value) in env::vars() {
// println!("环境变量内容:{}: {}", key, value);
// }
let connection_str = env::var("DATABASE_URL")
.expect("数据库连接字符串获取失败,请检查env文件是否已配置数据库连接字符串");
println!("数据库连接字符串是:{}", connection_str);
let pool = PgPoolOptions::new()
.max_connections(5)
.connect(&connection_str)
.await?;
println!("db_pool is : {:?}", pool);
//查询所有
let list = sqlx::query!("select * from course")
.fetch_all(&pool)
.await?;
let mut vec = vec![];
for row in list {
vec.push(Course {
id: row.id,
teacher_id: row.teacher_id,
name: row.name,
time: row.time,
})
}
println!("数据库中的所有数据:{:#?}", vec);
//查询单个
let list2 = sqlx::query!(r#"select * from course where id = $1"#, 1)
.fetch_all(&pool)
.await?;
let mut vec2 = vec![];
for row in list2 {
vec2.push(Course {
id: row.id,
teacher_id: row.teacher_id,
name: row.name,
time: row.time,
})
}
println!("查询单个{:#?}", vec2);
// 增加
let insert = sqlx::query!(
r#"INSERT INTO course VALUES ($1, $2, $3)"#,
100000,
11,
"gg"
)
.fetch_all(&pool)
.await?;
// 更新
let update = sqlx::query!(r#"update course set name=$1"#, "ogg")
.fetch_all(&pool)
.await?;
Ok(())
}
// cargo r
Hello, world!
数据库连接字符串是:postgres://postgres:pass@ip:5432/postgres
db_pool is : Pool { size: 1, num_idle: 1, is_closed: false, options: PoolOptions { max_connections: 5, min_connections: 0, connect_timeout: 30s, max_lifetime: Some(1800s), idle_timeout: Some(600s), test_before_acquire: true } }
数据库中的所有数据:[
Course {
id: 1,
teacher_id: 11,
name: "cml",
time: Some(
2022-03-25,
),
},
Course {
id: 2,
teacher_id: 22,
name: "cc",
time: Some(
2022-03-25,
),
},
Course {
id: 3,
teacher_id: 33,
name: "mm",
time: Some(
2022-03-25,
),
},
]
查询单个[
Course {
id: 1,
teacher_id: 11,
name: "cml",
time: Some(
2022-03-25,
),
},
]
// 执行完时,查询数据库如下:
postgres=# select * from course;
id | teacher_id | name | time
--------+------------+------+------------
1 | 11 | ogg | 2022-03-25
2 | 22 | ogg | 2022-03-25
3 | 33 | ogg | 2022-03-25
100000 | 11 | ogg | 2024-02-21
(4 rows)
参考:https://www.cnblogs.com/Naylor/p/16062584.html
2.2 query
let sql = format!(r#"DROP TABLE IF EXISTS {}"#, tmp_table_name);
let r = sqlx::query(&sql).execute(&pool).await?;
println!("sql: {} r: {:?}", sql, r);