Rust - 无法从 Rocket State 访问 r2d2 池连接

Posted

技术标签:

【中文标题】Rust - 无法从 Rocket State 访问 r2d2 池连接【英文标题】:Rust - Cannot Access r2d2 pool connection from Rocket State 【发布时间】:2021-10-31 08:06:16 【问题描述】:

我目前正在学习 Rust 和 Rocket

使用 Rust 1.54.0+Rocket 0.5.0_rc1+ Diesel 1.4.7 + r2d2 0.8.9

我用 r2d2 创建了一个 DB Postgres 连接池。我想在请求/路由之间共享连接池,为此我正在尝试使用 Rocket Managed State。 https://rocket.rs/v0.5-rc/guide/state/#managed-state

我创建了一个数据库连接池,将其保存在状态中,但是当我尝试从路由访问该数据库连接池时。我在同一行出现 2 个错误

Cell<i32> cannot be shared between threads safely

RefCell<HashMap<StatementCacheKey<Pg>, pg::connection::stmt::Statement>> cannot be shared between threads safely

这是我的代码

pub async fn establish_pooled_connection() -> Result<PooledConnection<ConnectionManager<PgConnection>>, r2d2_diesel::Error> 
    dotenv().ok();
    let database_url = env::var("DATABASE_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();
    Ok(conn)


struct DBPool
    db_pool: PooledConnection<ConnectionManager<PgConnection>>


#[rocket::main]
async fn main() 
  
    let pool = establish_pooled_connection();    
    rocket::build()
        .mount("/",routes![callapi])
        .manage(DBPooldb_pool: pool)
        .launch()
        .await.ok();       


#[post("/callapi", data = "<request>")]
async fn callapi(request: RequestAPI<'_>, _dbpool: &State<DBPool>) -> Json<models::api_response::ApiResponse> 
......

错误是针对这个参数的

_dbpool: &amp;State&lt;DBPool&gt;

提前致谢

【问题讨论】:

请提供minimal reproducible example。特别是State 是什么?还要编辑您的问题以添加 full 错误消息,包括上下文和编译器提出的建议。 @Jmb 我已经更新了问题,有更多细节,如果您有任何问题,请告诉我,谢谢 请包含 complete 错误消息,它应该以类似以下内容开头:“错误[E0277]:Cell&lt;i32&gt; 不能在线程之间安全共享”并以:“错误:由于先前的错误而中止”。请包括中间的所有行,它们对于我们了解错误的来源很重要。 【参考方案1】:

最后,我能够完成这项工作。

我主要使用这个 GitHub 存储库作为基础 https://github.com/practical-rust-web-development/mystore/tree/v1.1 仓库使用 Actix,但我使用的是 Rocket。

我认为我的主要错误理解是基本 PostgreSQL 连接是一个 PGConnection,而你从池中得到的是一个 PGPooledConnection,它最后是相同的。

这是我的代码

db_connection.rs

use diesel::pg::PgConnection;
use dotenv::dotenv;
use std::env;
use diesel::r2d2:: Pool, PooledConnection, ConnectionManager, PoolError ;

pub type PgPool = Pool<ConnectionManager<PgConnection>>;
pub type PgPooledConnection = PooledConnection<ConnectionManager<PgConnection>>;

//Connects to Postgres and call init pool
pub fn establish_connection() -> PgPool 
    dotenv().ok();

    let database_url = env::var("DATABASE_URL")
        .expect("DATABASE_URL must be set");
    init_pool(&database_url).expect("Failed to create pool")



//Creates a default R2D2 Postgres DB Pool
fn init_pool(database_url: &str) -> Result<PgPool, PoolError> 
    let manager = ConnectionManager::<PgConnection>::new(database_url);
    Pool::builder().build(manager)



//this functions returns a connection from the Pool
pub fn pg_pool_handler(pool: &PgPool) -> Result<PgPooledConnection, PoolError> 
    let _pool = pool.get().unwrap();
    Ok(_pool)

main.rs

mod db_connection;
use db_connection::PgPool;

#[rocket::main]
async fn main() 
    rocket::build()
        .mount("/API",routes![demo])
        .manage(db_connection::establish_connection()) //here is where you pass the pool to Rocket state.
        .launch()
        .await.ok();       


#[post("/demo", data = "<request>")]
async fn demo _dbpool: &State<PgPool>) -> Json<models::Response> 

let connection = db_connection::pg_pool_handler(_dbpool).unwrap();

let results = users.limit(1)
        .load::<User>(&connection)
        .expect("Error loading users");
........

这是基本代码,可以改进代码以更好地处理错误。

【讨论】:

以上是关于Rust - 无法从 Rocket State 访问 r2d2 池连接的主要内容,如果未能解决你的问题,请参考以下文章

Rocket 每晚需要最低版本的 Rust,但已经安装了更高的稳定版本

返回使用 Rocket 和 Diesel (Rust) 在 PostgreSQL 中创建的单个记录

如何设置(Rust)Rocket API 端点的模板响应的 HTTP 状态代码?

diesel.rs 和rocket.rs:不明白为啥它需要一个数据库表

推送通知在自定义应用程序中无法正常工作 [Rocket.chat]

“Hello world”Rust 网络服务器从 Chrome 测量而不是从 curl 测量时比 Node 慢