【rust】8、连接数据库:sqlx

sqlx 是 rust 的数据库访问工具, 本身并不是 orm,但常见的 orm 都是基于它实现的。其有如下特点:

  • 支持异步,适合高并发
  • 编译时检查:cargo build 时检查执行 sql,校验响应值
  • 支持多数据库:mysql、pg、sqlite 等
  • 支持主流 rust 运行时:tokio、async-std、actix、native-tls、rustls等
  • 内置连接池

一、数据库、依赖、环境变量

本文操作 pg,首先建表

sql 复制代码
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 新建项目,添加依赖:

bash 复制代码
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 文件,内容如下:

bash 复制代码
DATABASE_URL=postgres://cml:[email protected]:5432/postgres

二、增删改查

2.1 完整示例

  • dotenv().ok():在访问环境变量之前检查一下,防止因读取环境变量失败导致程序 panic。
  • env::var("DATABASE_URL"):读取环境变量文件中的数据库连接字符串
  • PgPoolOptions::new().connect():实例化一个数据库连接池
  • sqlx::query!("sql") .fetch_all(&pool):执行sql语句

工程目录结构:

bash 复制代码
│  .env
│  Cargo.toml 
├─src
│      main.rs

示例代码:

rust 复制代码
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

rust 复制代码
let sql = format!(r#"DROP TABLE IF EXISTS {}"#, tmp_table_name);
let r = sqlx::query(&sql).execute(&pool).await?;
println!("sql: {} r: {:?}", sql, r);
相关推荐
我命由我123451 小时前
Spring Boot 自定义日志打印(日志级别、logback-spring.xml 文件、自定义日志打印解读)
java·开发语言·jvm·spring boot·spring·java-ee·logback
叠叠乐4 小时前
rust Send Sync 以及对象安全和对象不安全
开发语言·安全·rust
·薯条大王4 小时前
MySQL联合查询
数据库·mysql
niandb5 小时前
The Rust Programming Language 学习 (九)
windows·rust
xyliiiiiL5 小时前
ZGC初步了解
java·jvm·算法
morris1316 小时前
【redis】redis实现分布式锁
数据库·redis·缓存·分布式锁
hycccccch6 小时前
Canal+RabbitMQ实现MySQL数据增量同步
java·数据库·后端·rabbitmq
这个懒人7 小时前
深入解析Translog机制:Elasticsearch的数据守护者
数据库·elasticsearch·nosql·translog
Yan-英杰7 小时前
【百日精通JAVA | SQL篇 | 第二篇】数据库操作
服务器·数据库·sql
NineData8 小时前
NineData云原生智能数据管理平台新功能发布|2025年3月版
数据库