数据库
databases.md
commit - 4d8d53cea59bca095ca5c02ef81f0b1791736855 - 2020.09.12
异步选项
我们有几个示例项目展示了异步数据库适配器的使用:
- SQLx: https://github.com/actix/examples/tree/master/sqlx_todo
- Postgres: https://github.com/actix/examples/tree/master/async_pg
- SQLite: https://github.com/actix/examples/tree/master/async_db
Diesel
当前版本的 Diesel(v1)不支持异步操作,因此使用 web::block
函数是非常重要的,此函数可以将数据库操作加载到 actix 的运行时线程池。
您可以创建操作函数,对应到应用程序对数据库执行的所有操作。
fn insert_new_user(db: &SqliteConnection, user: CreateUser) -> Result<User, Error> {
use self::schema::users::dsl::*;
// Create insertion model
let uuid = format!("{}", uuid::Uuid::new_v4());
let new_user = models::NewUser {
id: &uuid,
name: &user.name,
};
// normal diesel operations
diesel::insert_into(users)
.values(&new_user)
.execute(&self.0)
.expect("Error inserting person");
let mut items = users
.filter(id.eq(&uuid))
.load::<models::User>(&self.0)
.expect("Error loading person");
Ok(items.pop().unwrap())
}
您应该使用 r2d2
之类的 crate 来设置数据库池,这使得多个数据库连接可用于您的应用程序。还意味着多个 handler 可以同时操作数据库,并且仍然能够接受新的连接。简单地说,数据库连接池也是应用程序的状态(此种情况下,最好不要使用包裹状态为结构体,因为连接池为您处理共享访问)。
type DbPool = r2d2::Pool<ConnectionManager<SqliteConnection>>;
#[actix_web::main]
async fn main() -> io::Result<()> {
// Create connection pool
let pool = r2d2::Pool::builder()
.build(manager)
.expect("Failed to create pool.");
// Start HTTP server
HttpServer::new(move || {
App::new::data(pool.clone())
.resource("/{name}", web::get().to(index))
})
.bind("127.0.0.1:8080")?
.run()
.await
}
在请求 handler 中,使用 Data<T>
提取器从应用程序状态(app state)中获取数据库连接池,然后从中获取连接。这提供了一个可以传递到 web::block
闭包中的数据库连接,并对其具有所有权(owned)。然后,使用必要的参数调用操作函数,最后通过 .await
返回结果。
在示例中,将错误映射到 HttpResponse
,然后再使用 ?
运算符。但如果你返回的错误类型实现了 ResponseError
trait,则不需要执行此操作。
async fn index(pool: web::Data<DbPool>, name: web::Path<(String)>) -> impl Responder {
let name = name.into_inner();
let conn = pool.get().expect("couldn't get db connection from pool");
let user = web::block(move || actions::insert_new_user(&conn, &user))
.await
.map_err(|e| {
eprintln!("{}", e);
HttpResponse::InternalServerError().finish()
})?;
Ok(HttpResponse::Ok().json(user))
}
请参见此处的完整示例:https://github.com/actix/examples/tree/master/diesel