我正在尝试在一个生锈/柴油/火箭应用程序中实现连接池。我不知道如何确保只调用一次establish_pooled_connection()
方法的内容,以便准备连接池。
这是我的密码。
来自lib.rs
pub fn establish_pooled_connection() -> PooledConnection<ConnectionManager<PgConnection>> {
dotenv().ok();
let database_url = env::var("DB_URL")
.expect("DATABASE_URL must be set");
let manager = ConnectionManager::<PgConnection>::new(&database_url);
let pool = r2d2::Pool::builder().build(manager).expect("Failed to create pool.");
let conn = pool.clone().get().unwrap();
return conn;
}
在这里,我在main.rs中使用了上述方法
#[get("/", format = "json")]
fn find_all() -> Json<Vec<Person>> {
let connection = establish_pooled_connection();
let all: QueryResult<Vec<Person>> = person::table().get_results(&connection);
...
这里的问题是,每个get
方法(例如,上面)都调用establish_pooled_connection()
,并且所有东西都被重新实例化.
我来自java世界,依赖注入允许我们避免重新实例化。
在生锈/柴油应用程序中实现连接池的正确方法是什么?
发布于 2021-08-03 10:02:07
您不会在每个处理程序中创建一个新的连接,而是使用框架的一些状态共享机制。
有关如何在火箭中使用状态的指南,请参阅这里,这将是一个很好的起点。
发布于 2022-09-10 08:44:44
这里的问题是,每个get方法(例如,上面)都调用establish_pooled_connection(),并且所有东西都被重新实例化.
我在建立池连接方面也遇到了困难,所以我想我应该把我所做的抛在脑后。
我是怎么解决的
我设法使用火箭/柴油应用程序中的池连接,将已建立的池添加到服务器状态,并通过该服务器状态从各个函数访问数据库。
// add the `r2d2` feature for diesel
use diesel::{
r2d2::{ConnectionManager, Pool, PooledConnection},
MysqlConnection,
};
// set an alias, so we don't have to keep writing out this long type
pub type DbPool = Pool<ConnectionManager<MysqlConnection>>;
// a real-world app would have more fields in the server state like
// CORS options, environment values needed for external APIs, etc.
pub struct ServerState {
pub db_pool: DbPool
}
火箭允许我们在用.manage()
构建服务器时使用build()
调用定义服务器状态。
#[rocket::main]
pub async fn main() {
let db_pool: DbPool = establish_connection_pool();
rocket::build()
.mount("/", routes![test]) // mount routes
.manage(ServerState { db_pool })
.launch()
.await
.expect("Failed to launch rocket server.")
}
因为Rocket允许我们从函数中检索服务器的状态,只要它们有Rocket的宏(get
、post
等),我们就可以从服务器状态检索数据库。
use rocket::{get, serde::json::Json, State};
#[get("/test?<user_id>")]
pub async fn test(
state: &State<ServerState>,
user_id: String
) -> Result<Json<User>, Error> {
let pooled = &state.db_pool.get()?;
pooled.transaction(|| {
// some diesel query
})
}
我在这方面使用的版本如下所示。
diesel = { version = "1.4.8", features = ["r2d2", "mysql", "chrono"] }
rocket = { version = "0.5.0-rc.1", features = ["json"] }
还有什么要考虑的
正如我前面所做的,有些人希望直接使用r2d2
来设置池连接,这是有原因的。我个人认为,能够作为服务器状态中的字段传递到池中,将允许更好地控制编写集成测试。但是,您可能需要了解处理池连接的其他方法。
火箭提供了自己的解决方案,用rocket_sync_db_pools
1和rocket_db_pools
2处理池数据库连接。如果您在库中涵盖的数据库中使用diesel
3和sqlx
4之类的ORM,那么我强烈建议查看它们。
只需在项目的根目录中设置一个Rocket.toml
文件,如下所示。
[global.databases]
test_db = { url = "mysql://mysql:password@localhost:5432/test_db_name" }
现在,通过利用database
宏的强大功能,您可以轻松地建立连接。
#[macro_use]
extern crate rocket_sync_db_pools;
// as long as we set the `Rocket.toml` to include information about
// what database we want to point to, the `database` macro does
// the magic for us
#[database("test_db")]
pub struct TestDbConn(diesel::MysqlConnection);
// We can directly access the pooled connection as we did with the server state
#[get("/test?<user_id>")]
pub async fn test(
conn: TestDbConn,
user_id: String
) -> Result<Json<User>, Error> {
conn.run(move || {
// some diesel query
})
}
1将rocket_sync_db_pools
与diesel
这样的同步ORM结合使用。池/index.html#
2将rocket_db_pools
与异步ORM(如deadpool-postgres
和sqlx
)结合使用。池/index.html#
https://stackoverflow.com/questions/68633531
复制相似问题