Actix-web: How to use pooling of database inside functions using actix ?

Created on 17 Jul 2019  路  6Comments  路  Source: actix/actix-web

Hi,

I created a pool for MySQL database like this:

let database_url = env::var("DATABASE_URL").expect("set DATABASE_URL");

let manager = ConnectionManager::<MysqlConnection>::new(database_url);
let pool = r2d2::Pool::builder()
    .build(manager)
    .expect("Failed to create pool.");

Included inside actix like this:

HttpServer::new(move || App::new()
    .data(pool.clone()) // <-- HERE
    .service(
        web::resource("/infos")
          .route(web::post().to(get_infos))
    ))

    .bind("127.0.0.1:8080")?
    .start();

println!("Starting http server: 127.0.0.1:8080");

Here come the problem, how it's possible to use it inside this info function:

pub fn get_infos(conn: &MysqlConnection) -> Vec<Book> {
    all_books
        .order(books::id.desc())
        .load::<Book>(conn)
        .expect("error loading the books")
}

Passing directly one instance of MySQL connection to get_infos working well, but using pool I have no idea on how to process it ?! Any help please ?

For more clarification, my goal is to use POOLING instead of using one instance only like it's the case in this code:

let database_url = env::var("DATABASE_URL").expect("set DATABASE_URL");
let conn = MysqlConnection::establish(&database_url).unwrap();
// And then passing as argument "conn" to get_infos function.

I initiated the POOL to actix in the previous code:
.data(pool.clone()) // <-- HERE

But how to pass it as parameter to get_infos function.

Thanks again in advance for your help.

All 6 comments

You are passing the pool into your app data, not a connection so you have to get the connection from the pool.

pub fn get_infos(pool: web::Data<Pool<ConnectionManager<MysqlConnection>>>) -> Vec<Book> {
    let conn = db.get().unwrap();
    all_books.order(books::id.desc())
        .load::<Book>(&conn)
        .expect("error loading the books")
}

There is actually an example for r2d2 provided by actix.

Don鈥檛 forget to use web::block if your db is synchronous.

@kyle-mccarthy @fafhrd91 Thank you for your help :)

But what if I have 2 parameters in the function:

pub fn get_infos(form: web::Form<FormData>, pool: web::Data<Pool<ConnectionManager<MysqlConnection>>>) -> Vec<Book> {
    let conn = pool.get().unwrap();
    all_books.find(form.id)
        .load::<Book>(&conn)
        .expect("error loading the books")
}

//And then VVV
HttpServer::new(move || App::new()
    .data(pool.clone()) // <-- HERE
    .service(
        web::resource("/infos")
          .route(web::post().to(get_infos))
    ))

    .bind("127.0.0.1:8080")?
    .start();

println!("Starting http server: 127.0.0.1:8080");

This return an error and can't launch the function.

Is there a way to solve this issue ?

You should post your error

@fafhrd91 I am getting this error message:

App data is not configured, to configure use App::data()

Notice that I am using 2 parameters (
1- In order to catch POST requests from HTML form
2- To pass pool to the function
)

Thank you :)

Sorry problem solved - I data is not passed correctly.

Thank you all.

Was this page helpful?
0 / 5 - 0 ratings