You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Axum中通过共享状态注入PgConnection的并发锁问题

解决Axum中PgConnection共享导致的锁竞争问题

你当前的核心问题在于用Arc<Mutex<PgConnection>>共享单个数据库连接——同一时间只能有一个请求持有锁并使用连接,直接让Axum多Worker的并行能力完全失效,所有请求都会串行执行。

正确的做法是使用sqlx内置的数据库连接池(PgPool),连接池本身就是线程安全的,不需要额外加锁,还能自动管理连接的创建、复用与回收,完美适配Axum的并发模型。

步骤1:修改AppState结构

把单个连接替换成连接池:

use sqlx::postgres::PgPool;

pub struct AppState {
    pub db_pool: PgPool,
    pub jwt: JWTSettings,
}

步骤2:初始化连接池

在启动Axum服务时创建并初始化连接池:

async fn init_db_pool() -> PgPool {
    // 替换成你的数据库连接字符串
    PgPool::connect("postgres://user:password@localhost/your_db")
        .await
        .expect("Failed to initialize database pool")
}

#[tokio::main]
async fn main() {
    let db_pool = init_db_pool().await;
    let jwt_settings = JWTSettings::load().unwrap();
    let app_state = Arc::new(AppState { db_pool, jwt: jwt_settings });

    let app = Router::new()
        .route("/signup", post(sign_up))
        .with_state(app_state);

    axum::Server::bind(&"0.0.0.0:3000".parse().unwrap())
        .serve(app.into_make_service())
        .await
        .unwrap();
}

步骤3:路由中使用连接池

不需要锁,直接从池里异步获取连接,用完自动归还:

pub async fn sign_up(
    State(state): State<Arc<AppState>>,
    Json(signup_payload): Json<SignupPayload>,
) -> Result<Json<LoginResponse>, StatusCode> {
    // 异步获取连接,无可用连接时会挂起当前任务,不阻塞线程
    let connection = state.db_pool.acquire().await
        .map_err(|err| {
            eprintln!("Failed to get db connection: {:?}", err);
            StatusCode::INTERNAL_SERVER_ERROR
        })?;

    // 直接用连接执行查询,无需可变引用
    let existing_user = sqlx::query!("select * from users where username=$1", signup_payload.username)
        .fetch_one(&connection)
        .await
        .map_err(|err| {
            eprintln!("Query failed: {:?}", err);
            StatusCode::INTERNAL_SERVER_ERROR
        })?;

    // 后续业务逻辑...
    Ok(Json(LoginResponse { /* 填充响应字段 */ }))
}

为什么这能解决问题?

  • PgPool内部已经实现了线程安全的连接管理,无需额外的Mutex或Arc包装
  • acquire()是异步操作,不会阻塞线程,当连接池满时,请求会排队等待可用连接,其他请求仍能正常处理
  • 每个请求独立获取连接,多Worker线程可以并行处理不同请求,完全发挥Axum的并发优势

你还可以通过PgPoolOptions调整连接池的最大连接数、超时时间等参数,适配你的业务负载:

use sqlx::postgres::PgPoolOptions;

async fn init_db_pool() -> PgPool {
    PgPoolOptions::new()
        .max_connections(20) // 设置最大连接数
        .connect("postgres://user:password@localhost/your_db")
        .await
        .expect("Failed to initialize database pool")
}

内容的提问来源于stack exchange,提问作者Karan Kumar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 10:00:10