SeaORM 连接 seekdb 示例程序
本文将介绍如何使用 SeaORM 和 seekdb 构建一个应用程序,实现创建表、插入数据和查询数据等基本操作。
环境准备
在开始之前,请确保已安装以下工具:
- Rust 1.60 或更高版本
- Cargo (Rust 的包管理器)
- 已安装 seekdb
创建新项目
cargo new sea-orm-seekdb-demo
cd sea-orm-seekdb-demo
添加依赖
编辑 Cargo.toml 文件,添加以下依赖:
[package]
name = "sea-orm-seekdb-demo"
version = "0.1.0"
edition = "2021"
[dependencies]
tokio = { version = "1.0", features = ["full"] }
sea-orm = { version = "0.12", features = [
"sqlx-mysql",
"runtime-tokio-rustls",
"macros",
"with-json"
] }
sea-orm-migration = "0.12"
serde = { version = "1.0", features = ["derive"] }
dotenv = "0.15"
async-std = { version = "1.12", features = ["attributes"] }
chrono = "0.4"
配置数据库连接
在项目根目录创建 .env 文件:
DATABASE_URL=mysql://username:password@localhost:2881/database_name
定义实体
创建 src/entities 目录,并添加 mod.rs 和 user.rs 文件:
// src/entities/mod.rs
pub mod user;
// src/entities/user.rs
use sea_orm::entity::prelude::*;
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize)]
#[sea_orm(table_name = "users")]
pub struct Model {
#[sea_orm(primary_key)]
pub id: i32,
pub name: String,
pub email: String,
pub created_at: DateTimeUtc,
pub updated_at: DateTimeUtc,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {}
impl ActiveModelBehavior for ActiveModel {}
数据库连接
创建 src/db.rs:
use sea_orm::*;
use std::env;
use dotenv::dotenv;
pub async fn establish_connection() -> Result<DatabaseConnection, DbErr> {
dotenv().ok();
let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set");
Database::connect(&database_url).await
}
实现 CRUD 操作
创建 src/user_service.rs:
use crate::entities::user;
use sea_orm::*;
use chrono::Utc;
pub struct UserService;
impl UserService {
// 创建用户
pub async fn create_user(
db: &DatabaseConnection,
name: String,
email: String,
) -> Result<user::Model, DbErr> {
let new_user = user::ActiveModel {
name: Set(name),
email: Set(email),
created_at: Set(Utc::now()),
updated_at: Set(Utc::now()),
..Default::default()
};
new_user.insert(db).await
}
// 获取单个用户
pub async fn get_user(
db: &DatabaseConnection,
id: i32,
) -> Result<Option<user::Model>, DbErr> {
user::Entity::find_by_id(id).one(db).await
}
// 更新用户
pub async fn update_user(
db: &DatabaseConnection,
id: i32,
name: Option<String>,
email: Option<String>,
) -> Result<user::Model, DbErr> {
let mut user: user::ActiveModel = user::Entity::find_by_id(id)
.one(db)
.await?
.ok_or_else(|| DbErr::Custom("User not found".to_owned()))?
.into();
if let Some(name) = name {
user.name = Set(name);
}
if let Some(email) = email {
user.email = Set(email);
}
user.updated_at = Set(Utc::now());
user.update(db).await
}
// 删除用户
pub async fn delete_user(
db: &DatabaseConnection,
id: i32,
) -> Result<DeleteResult, DbErr> {
let user: user::ActiveModel = user::Entity::find_by_id(id)
.one(db)
.await?
.ok_or_else(|| DbErr::Custom("User not found".to_owned()))?
.into();
user.delete(db).await
}
// 获取所有用户
pub async fn get_all_users(
db: &DatabaseConnection,
) -> Result<Vec<user::Model>, DbErr> {
user::Entity::find().all(db).await
}
}
主程序
修改 src/main.rs:
mod entities;
mod db;
mod user_service;
use sea_orm::{DatabaseConnection, DbErr, Statement, ConnectionTrait};
use user_service::UserService;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// 建立数据库连接
println!("Connecting to database...");
let db = db::establish_connection().await?;
println!("Database connected successfully!");
// 创建表(如果不存在)
println!("Creating tables if not exist...");
create_tables(&db).await?;
println!("Tables created successfully!");
// 创建用户
println!("Inserting sample data...");
let users_to_create = vec![
("Alice", "alice@example.com"),
("Bob", "bob@example.com"),
("Charlie", "charlie@example.com"),
];
for (name, email) in users_to_create {
println!("Creating user: {} <{}>", name, email);
match UserService::create_user(
&db,
name.to_string(),
email.to_string()
).await {
Ok(user) => println!("Created user: {} <{}>", user.name, user.email),
Err(e) => eprintln!("Error creating user: {}", e),
}
}
// 获取所有用户并打印
println!("\nCurrent users in database:");
match UserService::get_all_users(&db).await {
Ok(users) => {
for user in users {
println!("ID: {}, Name: {}, Email: {}, Created: {}, Updated: {}",
user.id, user.name, user.email, user.created_at, user.updated_at);
}
},
Err(e) => eprintln!("Error fetching users: {}", e),
}
Ok(())
}
async fn create_tables(db: &DatabaseConnection) -> Result<(), DbErr> {
let stmt = r#"
CREATE TABLE IF NOT EXISTS users (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
email VARCHAR(255) NOT NULL UNIQUE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
"#;
db.execute(Statement::from_string(
db.get_database_backend(),
stmt.to_owned(),
))
.await?;
Ok(())
}
运行程序
cargo run
预期返回结果如下:
Connecting to database...
Database connected successfully!
Creating tables if not exist...
Tables created successfully!
Inserting sample data...
Creating user: Alice <alice@example.com>
Creating user: Bob <bob@example.com>
Creating user: Charlie <charlie@example.com>
Current users in database:
ID: 1, Name: Alice, Email: alice@example.com, Created: 2025-05-27 09:47:01 UTC, Updated: 2025-05-27 09:47:01 UTC
ID: 2, Name: Bob, Email: bob@example.com, Created: 2025-05-27 09:47:01 UTC, Updated: 2025-05-27 09:47:01 UTC
ID: 3, Name: Charlie, Email: charlie@example.com, Created: 2025-05-27 09:47:01 UTC, Updated: 2025-05-27 09:47:01 UTC