1. Cargo.toml配置文件

[package]
name = "rust-sqlx"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
sqlx = { version = "0.7", features = [ "runtime-async-std", "tls-native-tls", "mysql", "macros", "chrono" ] }
async-std = {version = "1.12.0", features = ["attributes"]}
chrono = "0.4.38"

\quad\quad cargo.toml配置文件可参考crates.io进行配置,但有几点值得注意❗ ❗ ❗:

  • 如果选择runtime-async-std异步运行时,则需要开启它的attributesfeatures。否则在源文件中,入口函数处的#[async_std::main]会报错。
  • sqlxfeatures中需要添加mysql。否则use sqlx::mysql::MySqlPoolOptions;会报错。
  • sqlxfeatures中需要添加chrono。 否则无法完成数据库中datetime类型到chrono::NaiveDateTime类型的转换。
  • sqlxfeatures中需要添加macros。否则query!()以及query_as!()等宏会报错。
  • 由于是简单的入门程序,dotenvy以及序列化等crates暂时未引入。

\quad\quad sqlxCargo Feature Flagscrates.io-sqlx界面亦有介绍,下面是部分摘录:

  • postgres: Add support for the Postgres database server.

  • mysql: Add support for the MySQL/MariaDB database server.

  • mssql: Add support for the MSSQL database server.

  • sqlite: Add support for the self-contained SQLite database engine.

  • any: Add support for the Any database driver, which can proxy to a database driver at runtime.

  • derive: Add support for the derive family macros, those are FromRow, Type, Encode, Decode.

  • macros: Add support for the query*! macros, which allows compile-time checked queries.

  • migrate: Add support for the migration management and migrate! macro, which allow compile-time embedded migrations.

  • uuid: Add support for UUID (in Postgres).

  • chrono: Add support for date and time types from chrono.

  • time: Add support for date and time types from time crate (alternative to chrono, which is preferred by query! macro, if both enabled)

  • bstr: Add support for bstr::BString.

  • bigdecimal: Add support for NUMERIC using the bigdecimal crate.

  • rust_decimal: Add support for NUMERIC using the rust_decimal crate.

  • ipnetwork: Add support for INET and CIDR (in postgres) using the ipnetwork crate.

  • json: Add support for JSON and JSONB (in postgres) using the serde_json crate.

2. 数据库中表结构

dept数据表

\quad\quad 在这里我的表结构如上所示。这个比较自由,根据自身实际情况选择即可。

3. 简单测试

\quad\quad 源文件主要修改自crates.io-sqlx中的示例程序。

❗❗❗ 注意,由于每个人的数据库密码,数据库名称,数据表的内容不尽相同,下面代码只具有参考意义,具体部分需要修改。

// use sqlx::postgres::PgPoolOptions;
use sqlx::mysql::MySqlPoolOptions;
use sqlx::Row;
use chrono::NaiveDateTime;
// etc.

/**
*	根据注释信息,我们提前在toml文件中设置以下内容,开启对应的feature
*	async-std = {version = "1.12.0", features = ["attributes"]}
*/
#[async_std::main] // Requires the `attributes` feature of `async-std`
// or #[tokio::main]
// or #[actix_web::main]
async fn main() -> Result<(), sqlx::Error> {
    let pool = MySqlPoolOptions::new()
                .max_connections(5)
                .connect("mysql://username:password@localhost/data_base_name").await?;

	// `table_name`为你自己的表名称
    let rows = sqlx::query("select * from table_name").fetch_all(&pool).await?;

    // 如果想要使用`get`函数通过索引列名访问数据,需要提前引入`sqlx::Row`
    /**
	*	get::<T, U>("column_name")
	*		其中`T`对应于`rust`程序中的类型
	*		其中`U`对应于查询类型,这里我们采用的是列名而不是索引,因此是`&str`
	*/
    for row in rows.iter() {
        println!("id {}, name {}, create_time {}", 
                row.get::<u32, &str>("id"), 
                row.get::<String, &str>("name"),
                row.get::<NaiveDateTime, &str>("create_time")
            );
    }

    Ok(())
}

\quad\quad 在这里值得注意是,get函数需要指定第一个泛型参数,帮助rust进行类型推断。
\quad\quad 执行cargo run --release之后,在控制台便会输出

    Finished release [optimized] target(s) in 0.19s
     Running `target\release\rust-sqlx.exe`
id 1, name 学工部, create_time 2024-03-26 21:53:41
id 2, name 教研部, create_time 2024-03-26 21:53:41
id 3, name 咨询部, create_time 2024-03-26 21:53:41
id 4, name 就业部, create_time 2024-03-26 21:53:41
id 5, name 人事部, create_time 2024-03-26 21:53:41

4. FromRow完成自动映射

\quad\quad 上述代码需要手动的将数据库查询结果取出,并转换为对应的rust语言中的程序类型。显然是不符合实际情况的,需要想办法解决。

4.1 自定义结构体

\quad\quad 我们可以自定义一个结构体,让它代表数据表中记录数据的类型。

use chrono::NaiveDateTime;
use sqlx::FromRow;

#[derive(Debug, FromRow)]
pub struct Dept {
    id: u32,
    name: String,
    create_time: NaiveDateTime,
    update_time: NaiveDateTime,
}

\quad\quad 其中 FromRow这个trait完成了从表中的一条记录到程序中一个对象实例的转变。

4.2 代码分层

src
├─ dataobj
│ ├─ dept.rs
│ └─ mod.rs
└─ main.rs

\quad\quad 将代码划分成如上的属性结构。下面给出各部分的代码:

  1. dataobj/dept.rs部分
use chrono::NaiveDateTime;
use sqlx::FromRow;

#[derive(Debug, FromRow)]
pub struct Dept {
   id: u32,
   name: String,
   create_time: NaiveDateTime,
   update_time: NaiveDateTime,
}
  1. dataobj/mod.rs部分
pub mod dept;

  1. main.rs部分
use sqlx::mysql::MySqlPoolOptions;
use sqlx::Row;
use chrono::NaiveDateTime;

mod dataobj;
use dataobj::dept::Dept;

#[async_std::main] // Requires the `attributes` feature of `async-std`
async fn main() -> Result<(), sqlx::Error> {
    let pool = MySqlPoolOptions::new()
                .max_connections(5)
                .connect("mysql://username:password@host/database_name").await?;


	// `table_name`为你自己的表名称
    let rows = sqlx::query("select * from table_name").fetch_all(&pool).await?;

    println!("使用`query()`, 需要手动转换结果");
    // 如果想要使用`get`函数通过索引列名访问数据,需要提前引入`sqlx::Row`
    for row in rows.iter() {
        println!("id {}, name {}, create_time {}", 
                row.get::<u32, &str>("id"), 
                row.get::<String, &str>("name"),
                row.get::<NaiveDateTime, &str>("create_time")
            );
    }


    println!();
    let depts: Vec<Dept> = sqlx::query_as("select * from table_name").fetch_all(&pool).await?;
    
    println!("使用`query_as()`, 将查询结果转为自定义结构体");
    for dept in depts.iter() {
        println!("{:#?}", dept);
    }


    println!();
    let single_dept: Dept = sqlx::query_as("select * from table_name where id = ?")
            .bind(1)
            .fetch_one(&pool)
            .await?;
    println!("表中id为1的元素是: \n{:#?}", single_dept);

    Ok(())
}

\quad\quad 输出结果如下

使用`query()`, 需要手动转换结果
id 1, name 学工部, create_time 2024-03-26 21:53:41
id 2, name 教研部, create_time 2024-03-26 21:53:41
id 3, name 咨询部, create_time 2024-03-26 21:53:41
id 4, name 就业部, create_time 2024-03-26 21:53:41
id 5, name 人事部, create_time 2024-03-26 21:53:41

使用`query_as()`, 将查询结果转为自定义结构体
Dept {
    id: 1,
    name: "学工部",
    create_time: 2024-03-26T21:53:41,
    update_time: 2024-03-26T21:53:41,
}
Dept {
    id: 2,
    name: "教研部",
    create_time: 2024-03-26T21:53:41,
    update_time: 2024-03-26T21:53:41,
}
Dept {
    id: 3,
    name: "咨询部",
    create_time: 2024-03-26T21:53:41,
    update_time: 2024-03-26T21:53:41,
}
Dept {
    id: 4,
    name: "就业部",
    create_time: 2024-03-26T21:53:41,
    update_time: 2024-03-26T21:53:41,
}
Dept {
    id: 5,
    name: "人事部",
    create_time: 2024-03-26T21:53:41,
    update_time: 2024-03-26T21:53:41,
}

表中id为1的元素是: 
Dept {
    id: 1,
    name: "学工部",
    create_time: 2024-03-26T21:53:41,
    update_time: 2024-03-26T21:53:41,
}
Logo

开放原子旋武开源社区(简称“旋武社区”)是由开放原子开源基金会孵化及运营的技术社区,致力于在中国推广和发展Rust编程语言生态,推动Rust在操作系统、终端设备、安全技术、基础软件等关键领域的产业落地,构建安全、可靠、高效的软件基础设施。

更多推荐