Rust 的 sqlx crate 提供了型別安全且非同步的資料函式庫操作方式,本文將逐步示範如何使用 sqlx 連線 PostgreSQL 資料函式庫,並進行資料函式庫的建立、使用者設定、資料表設計以及資料查詢等操作。同時,我們也將探討如何結合 Actix Web 框架,開發一個以資料函式庫為核心的 Web 服務,包含路由設定、請求處理以及單元測試等環節,以確保程式碼的健壯性和可靠性。最後,我們將深入研究如何定義資料模型,並將 HTTP 請求的資料轉換為 Rust 資料結構,以便於後續的資料函式庫操作。
在 PostgreSQL 中建立資料函式庫與使用者並連線 Rust 程式
STEP 3: 建立 PostgreSQL 資料函式庫與使用者
首先,我們需要進入 PostgreSQL 命令列介面。登入 PostgreSQL 使用者帳戶後,執行以下指令:
psql
此時,你應該會看到 postgres=# 的提示符號。接著,建立一個名為 ezytutors 的資料函式庫:
postgres=# create database ezytutors;
建立一個新的使用者 truuser 並設定密碼:
postgres=# create user truuser with password 'mypassword';
將新建立的使用者加入至 ezytutors 資料函式庫的存取許可權:
postgres=# grant all privileges on database ezytutors to truuser;
完成後,離開 PostgreSQL 命令列介面:
postgres=# \q
離開 PostgreSQL 使用者帳戶:
exit
設定環境變數 DATABASE_USER 為剛才建立的使用者名稱:
export DATABASE_USER=truuser
使用以下指令登入 ezytutors 資料函式庫:
psql -U $DATABASE_USER -d ezytutors --password
輸入密碼後,你應該會看到 ezytutors=> 的提示符號。執行 \list 指令確認資料函式庫是否建立成功。
PostgreSQL 資料函式庫建立流程
@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle
title Rust與PostgreSQL資料函式庫連線與操作
package "機器學習流程" {
package "資料處理" {
component [資料收集] as collect
component [資料清洗] as clean
component [特徵工程] as feature
}
package "模型訓練" {
component [模型選擇] as select
component [超參數調優] as tune
component [交叉驗證] as cv
}
package "評估部署" {
component [模型評估] as eval
component [模型部署] as deploy
component [監控維護] as monitor
}
}
collect --> clean : 原始資料
clean --> feature : 乾淨資料
feature --> select : 特徵向量
select --> tune : 基礎模型
tune --> cv : 最佳參數
cv --> eval : 訓練模型
eval --> deploy : 驗證模型
deploy --> monitor : 生產模型
note right of feature
特徵工程包含:
- 特徵選擇
- 特徵轉換
- 降維處理
end note
note right of eval
評估指標:
- 準確率/召回率
- F1 Score
- AUC-ROC
end note
@enduml
圖表翻譯: 此圖示呈現了建立 PostgreSQL 資料函式庫與使用者的步驟順序,從登入 PostgreSQL 開始,建立資料函式庫、使用者、授權,最後登入並確認資料函式庫列表。
STEP 4: 定義 Rust 資料函式庫模型並建立資料表
在 Rust 專案中定義資料函式庫模型並建立資料表。首先,建立一個 database.sql 檔案於專案根目錄下的 src 資料夾中,並加入以下 SQL 指令碼:
/* Drop table if it already exists*/
drop table if exists ezy_course_c4;
/* Create a table. */
create table ezy_course_c4
(
course_id serial primary key,
tutor_id INT not null,
course_name varchar(140) not null,
posted_time TIMESTAMP default now()
);
/* Load seed data for testing */
insert into ezy_course_c4 (course_id, tutor_id, course_name, posted_time)
values (1, 1, 'First course', '2020-12-17 05:40:00');
insert into ezy_course_c4 (course_id, tutor_id, course_name, posted_time)
values (2, 1, 'Second course', '2020-12-18 05:45:00');
執行以下指令以套用 SQL 指令碼至 ezytutors 資料函式庫:
psql -U $DATABASE_USER -d ezytutors < $PROJECT_ROOT/src/database.sql
確認資料是否成功寫入 ezy_course_c4 資料表:
psql -U $DATABASE_USER -d ezytutors --password
select * from ezy_course_c4;
你應該會看到類別似以下的結果:
course_id | tutor_id | course_name | posted_time
---
-
---
-
---
+
---
-
---
---
+
---
-
---
-
---
---
+
---
-
---
-
---
-
---
-
---
--
1 | 1 | First course | 2020-12-17 05:40:00
2 | 1 | Second course | 2020-12-18 05:45:00
(2 rows)
STEP 5: 編寫 Rust 程式碼連線資料函式庫並查詢資料表
在 src/bin/iter1.rs 中加入以下 Rust 程式碼:
use dotenv::dotenv;
use std::env;
use std::io;
use sqlx::postgres::PgPool;
use chrono::NaiveDateTime;
#[derive(Debug)]
pub struct Course {
pub course_id: i32,
pub tutor_id: i32,
pub course_name: String,
pub posted_time: Option<NaiveDateTime>,
}
#[actix_rt::main]
async fn main() -> io::Result<()> {
dotenv().ok();
let database_url = env::var("DATABASE_URL").expect("DATABASE_URL is not set in .env file");
let db_pool = PgPool::connect(&database_url).await.unwrap();
let course_rows = sqlx::query!(
r#"select course_id, tutor_id, course_name, posted_time from ezy_course_c4 where course_id = $1"#,
1
)
.fetch_all(&db_pool)
.await
.unwrap();
let mut courses_list = vec![];
for course_row in course_rows {
courses_list.push(Course {
course_id: course_row.course_id,
tutor_id: course_row.tutor_id,
course_name: course_row.course_name,
posted_time: Some(chrono::NaiveDateTime::from(course_row.posted_time.unwrap())),
})
}
println!("Courses = {:?}", courses_list);
Ok(())
}
程式碼解密:
- 載入
.env檔案中的環境變數。 - 從環境變數中讀取
DATABASE_URL。 - 使用
sqlx連線到 PostgreSQL 資料函式庫。 - 對
ezy_course_c4資料表執行 SQL 查詢,篩選出course_id = 1的資料。 - 將查詢結果轉換為
Course結構體並存入向量中。 - 列印查詢結果。
此程式碼展示瞭如何使用 Rust 連線到 PostgreSQL 資料函式庫並執行查詢操作。透過使用 sqlx 和 dotenv 等 crate,我們能夠簡化資料函式庫操作和環境變數的管理。
使用 Rust 和 sqlx 連線 Postgres 資料函式庫
在前面的章節中,我們已經成功地使用 sqlx 連線到 Postgres 資料函式庫。在本章節中,我們將進一步探討如何建立一個資料函式庫驅動的 Web 服務。
設定資料函式庫連線
首先,我們需要在專案根目錄中建立一個 .env 檔案,並新增以下內容:
DATABASE_URL=postgres://<my-user>:<mypassword>@127.0.0.1:5432/ezytutors
請將 <my-user> 和 <mypassword> 替換為您在設定資料函式庫時使用的使用者名稱和密碼。5432 是 Postgres 伺服器的預設連線埠,ezytutors 是我們要連線的資料函式庫名稱。
建立資料函式庫連線池
接下來,我們將使用 sqlx 建立一個資料函式庫連線池。這有助於在 Actix Web 框架產生的多個執行緒中有效地管理資料函式庫連線。
use sqlx::postgres::PgPool;
pub struct AppState {
pub health_check_response: String,
pub visit_count: Mutex<u32>,
pub db: PgPool,
}
在 AppState 結構體中,我們保留了前一章節中需要的兩個欄位,並增加了一個新的欄位 db,代表 sqlx Postgres 連線池。
定義資料模型
現在,讓我們在 src/iter2/models.rs 檔案中定義資料模型。在這裡,我們將定義一個資料結構來表示課程,並編寫一個實用方法,將 HTTP POST 請求中傳送的 JSON 資料負載轉換為 Rust Course 資料結構。
use actix_web::web;
use chrono::NaiveDateTime;
use serde::{Deserialize, Serialize};
#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct Course {
pub course_id: i32,
pub tutor_id: i32,
pub course_name: String,
pub posted_time: Option<NaiveDateTime>,
}
impl From<web::Json<Course>> for Course {
fn from(course: web::Json<Course>) -> Self {
Course {
course_id: course.course_id,
tutor_id: course.tutor_id,
course_name: course.course_name.clone(),
posted_time: course.posted_time,
}
}
}
資料模型解密:
Course資料結構包含課程 ID、導師 ID、課程名稱和發布時間等欄位。其中,posted_time欄位是Optional<T>型別,因為對於新的課程發布,該欄位將由導師 Web 服務自動填充,使用者無需提供此資訊。From特性將提取 HTTP POST 請求中傳送的資料負載,並將其轉換為 RustCourse資料結構。
設定路由
在 src/iter2/routes.rs 檔案中,我們將定義路由。
use super::handlers::*;
use actix_web::web;
pub fn general_routes(cfg: &mut web::ServiceConfig) {
cfg.route("/health", web::get().to(health_check_handler));
}
pub fn course_routes(cfg: &mut web::ServiceConfig) {
cfg.service(
web::scope("/courses")
.route("/", web::post().to(post_new_course))
.route("/{tutor_id}", web::get().to(get_courses_for_tutor))
.route("/{tutor_id}/{course_id}", web::get().to(get_course_details)),
);
}
路由解密:
general_routes函式定義了/health路由,用於檢查服務的健康狀態。course_routes函式定義了/courses路由,包括三個子路由:POST /courses:用於建立新的課程。GET /courses/{tutor_id}:用於檢索特定導師的所有課程。GET /courses/{tutor_id}/{course_id}:用於檢索特定課程的詳細資訊。
編寫單元測試
在本章節中,我們還將編寫單元測試,以確保 Web 服務的正確性。