サンプル集  >  Rust  >  MySQLのデータ検索(SQLx)②
MySQLのデータ検索(SQLx)②
2025/12/06

RustでSQLxクレートを使ってMySQLのデータを検索してみます。

  1. プロジェクトの作成
  2. プログラム作成
◆環境
OS Windows 11 Home 25H2
rustc 1.91.1
cargo 1.91.1

プロジェクトの作成

プロジェクトを作成します。

cargo new sqlxtest2

コマンドプロンプトでプロジェクトを作成したいフォルダへ移動しコマンドを実行します。

cargo new sqlxtest2
    Creating binary (application) `sqlxtest` package
note: see more `Cargo.toml` keys and their definitions at https://doc
.rust-lang.org/cargo/reference/manifest.html

プログラム作成

ポイントは以下になります。

  1. コネクションプールを使う。(MySqlPoolOptions::new())
  2. プリペアドステートメントを使う。(?とbind())
  3. 接続文字列はハードコーディングせず.envで管理する。
  4. sqlx::query_as!でコンパイル時にSQLの検証をする。

Cargo.toml
 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
[package]
name = "sqlxtest2"
version = "0.1.0"
edition = "2024"

[dependencies]
sqlx = { version = "0.7", features = ["mysql"
                                    , "runtime-tokio"
                                    , "macros"
                                    , "rust_decimal"
                                    , "chrono"
                                    ] }
tokio = { version = "1", features = ["full"] }
dotenvy = "0.15"
rust_decimal = "1"
anyhow = "1"
chrono = "0.4"

main.rs
 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
20: 
21: 
22: 
23: 
24: 
25: 
26: 
27: 
28: 
29: 
30: 
31: 
32: 
33: 
34: 
35: 
36: 
37: 
38: 
39: 
40: 
41: 
42: 
43: 
44: 
45: 
46: 
47: 
48: 
49: 
50: 
51: 
52: 
53: 
54: 
55: 
56: 
57: 
58: 
59: 
60: 
61: 
62: 
63: 
64: 
65: 
66: 
67: 
68: 
69: 
70: 
71: 
72: 
73: 
use sqlx::mysql::{MySqlPool, MySqlPoolOptions};
use anyhow::Result;
use rust_decimal::Decimal;
use chrono::NaiveDateTime;
use std::{thread, time};

#[derive(Debug, sqlx::FromRow)]
struct Rec {
    id: i64,
    rec_date: NaiveDateTime,
    rec_value: Option<Decimal>,
}

async fn get_rec(pool: &MySqlPool, id: i64) -> Result<Rec> {

    let rec = sqlx::query_as!(Rec,
        "SELECT * FROM rec_values WHERE id=?",
        id
    )
    .fetch_optional(pool)
    .await?
    .ok_or_else(|| anyhow::anyhow!("id not found: {}", id))?;

    Ok(rec)
}

#[tokio::main]
async fn main() -> Result<()> {
    println!("Hello, world!");
    dotenvy::dotenv().ok();

    let database_user = std::env::var("DATABASE_USER")?;
    let database_pass = std::env::var("DATABASE_PASS")?;
    let database_host = std::env::var("DATABASE_HOST")?;
    let database_port = std::env::var("DATABASE_PORT")?;
    let database_db   = std::env::var("DATABASE_DB")?;

    let connection_string
    = format!("mysql://{}:{}@{}:{}/{}"
            , database_user
            , database_pass
            , database_host
            , database_port
            , database_db
            );
    println!("{}",connection_string);

    let pool = MySqlPoolOptions::new()
        .max_connections(10)
        .connect(&connection_string)
        .await?;

    let id = 1;
    let rec = get_rec(&pool, id).await?;

    // rec_value は Option なので match で表示
    match rec.rec_value {
        Some(v) => println!("id={} date={} value={}"
                          , rec.id
                          , rec.rec_date
                          , v
                          ),
        None    => println!("id={} date={} value=NULL"
                          , rec.id
                          , rec.rec_date
                          ),
    }

    // 接続数確認のため5秒スリープ
    thread::sleep(time::Duration::from_secs(5));

    Ok(())
}

DBはDocker上に構築していてlocalhost:13306で待ち受けているのでポートは13306にしました。

docker container restart mysql-container-8.0.41

.env
1: 
2: 
3: 
4: 
5: 
DATABASE_USER=root
DATABASE_PASS=root
DATABASE_HOST=localhost
DATABASE_PORT=13306
DATABASE_DB=MyDB

テーブルとテストデータは MySQLのデータ検索(SQLx) で作成したものを使います。

実行してみます。

PS C:\src\sqlxtest2> cargo run
   Compiling sqlxtest2 v0.1.0 (C:\src\sqlxtest2)
error: set `DATABASE_URL` to use query macros online, or run `cargo s
qlx prepare` to update the query cache
  --> src\main.rs:16:15
   |
16 |       let rec = sqlx::query_as!(Rec,
   |  _______________^
17 | |         "SELECT * FROM rec_values WHERE id=?",
18 | |         id
19 | |     )
   | |_____^
   |
   = note: this error originates in the macro `$crate::sqlx_macros::e
xpand_query` which comes from the expansion of the macro `sqlx::que
ry_as` (in Nightly builds, run with -Z macro-backtrace for more inf
o)

error: could not compile `sqlxtest2` (bin "sqlxtest2") due to 1 previ
ous error

エラーになりました。DATABASE_URLを指定する必要があるようです。 .envファイルにDATABASE_URLを追加します。

.env
1: 
2: 
3: 
4: 
5: 
6: 
DATABASE_USER=root
DATABASE_PASS=root
DATABASE_HOST=localhost
DATABASE_PORT=13306
DATABASE_DB=MyDB
DATABASE_URL="mysql://root:root@localhost:13306/MyDB"

実行してみます。

PS C:\src\sqlxtest2> cargo run
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.24s
     Running `target\debug\sqlxtest2.exe`
Hello, world!
mysql://root:root@localhost:13306/MyDB
id=1 date=2026-03-15 09:22:16 value=12.3

見た感じは特に変わりがなく期待通りに動作しました。

テーブル名を間違えてみます。

PS C:\src\sqlxtest2> cargo run
   Compiling sqlxtest2 v0.1.0 (C:\src\sqlxtest2)
error: error returned from database: 1146 (42S02): Table 'MyDB.rec_va
lue' doesn't exist
  --> src\main.rs:16:15
   |
16 |       let rec = sqlx::query_as!(Rec,
   |  _______________^
17 | |         "SELECT * FROM rec_value WHERE id=?",
18 | |         id
19 | |     )
   | |_____^
   |
   = note: this error originates in the macro `$crate::sqlx_macros::e
xpand_query` which comes from the expansion of the macro `sqlx::que
ry_as` (in Nightly builds, run with -Z macro-backtrace for more inf
o)

error: could not compile `sqlxtest2` (bin "sqlxtest2") due to 1 previ
ous error

SQL文を間違えてみます。

PS C:\src\sqlxtest2> cargo run
   Compiling sqlxtest2 v0.1.0 (C:\src\sqlxtest2)
error: error returned from database: 1064 (42000): You have an error 
in your SQL syntax; check the manual that corresponds to your MySQL
 server version for the right syntax to use near 'rec_values WHERE 
id=?' at line 1
  --> src\main.rs:16:15
   |
16 |       let rec = sqlx::query_as!(Rec,
   |  _______________^
17 | |         "SELECT * rec_values WHERE id=?",
18 | |         id
19 | |     )
   | |_____^
   |
   = note: this error originates in the macro `$crate::sqlx_macros::e
xpand_query` which comes from the expansion of the macro `sqlx::que
ry_as` (in Nightly builds, run with -Z macro-backtrace for more inf
o)

error: could not compile `sqlxtest2` (bin "sqlxtest2") due to 1 previ
ous error

接続文字列はDATABASE_URLがそのままで使えました。

main.rs
 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
20: 
21: 
22: 
23: 
24: 
25: 
26: 
27: 
28: 
29: 
30: 
31: 
32: 
33: 
34: 
35: 
36: 
37: 
38: 
39: 
40: 
41: 
42: 
43: 
44: 
45: 
46: 
47: 
48: 
49: 
50: 
51: 
52: 
53: 
54: 
55: 
56: 
57: 
58: 
59: 
60: 
use sqlx::mysql::{MySqlPool, MySqlPoolOptions};
use anyhow::Result;
use rust_decimal::Decimal;
use chrono::NaiveDateTime;
use std::{thread, time};

#[derive(Debug, sqlx::FromRow)]
struct Rec {
    id: i64,
    rec_date: NaiveDateTime,
    rec_value: Option<Decimal>,
}

async fn get_rec(pool: &MySqlPool, id: i64) -> Result<Rec> {

    let rec = sqlx::query_as!(Rec,
        "SELECT * FROM rec_values WHERE id=?",
        id
    )
    .fetch_optional(pool)
    .await?
    .ok_or_else(|| anyhow::anyhow!("id not found: {}", id))?;

    Ok(rec)
}

#[tokio::main]
async fn main() -> Result<()> {
    println!("Hello, world!");
    dotenvy::dotenv().ok();

    let connection_string = std::env::var("DATABASE_URL")?;
    println!("{}",connection_string);

    let pool = MySqlPoolOptions::new()
        .max_connections(10)
        .connect(&connection_string)
        .await?;

    let id = 1;
    let rec = get_rec(&pool, id).await?;

    // rec_value は Option なので match で表示
    match rec.rec_value {
        Some(v) => println!("id={} date={} value={}"
                          , rec.id
                          , rec.rec_date
                          , v
                          ),
        None    => println!("id={} date={} value=NULL"
                          , rec.id
                          , rec.rec_date
                          ),
    }

    // 接続数確認のため5秒スリープ
    thread::sleep(time::Duration::from_secs(5));

    Ok(())
}

SQLをチェックできるのは便利ですね。

関連項目

Docker MySQL
MySQLでテーブル作成、データ追加、検索
MySQLのデータ検索(SQLx)
MySQLのデータ追加(SQLx)

▲ PageTop  ■ Home


Copyright (C) 2026 ymlib.com