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

基于Tokio与Axum实现异步数据库连接池的延迟初始化

全局异步数据库连接池结构体的延迟初始化方案

需求

希望一次性延迟初始化包含异步数据库连接池的结构体,并能在全局各处使用。

现有基础代码

最初定义的Database结构体及异步初始化方法如下:

#[derive(Debug)]
pub struct Database {
    pub pool: PgPool,
}

impl Database {
    pub async fn init() -> Self {
        let pool = Database::create_db_pool().await;

        Database { pool }
    }

    pub async fn create_db_pool() -> PgPool {
        PgPoolOptions::new()
            .max_connections(20)
            .acquire_timeout(Duration::from_secs(3))
            .connect(API_ENV.db_url)
            .await
            .expect("Can't connect to database")
    }
}

尝试的方案及问题

方案1:使用OnceCell

通过OnceCell实现全局实例,但每次调用都需要写DATABASE.get().unwrap(),不够简洁:

pub static DATABASE: OnceCell<Database> = OnceCell::new();

async fn main() {
    let db = Database::init().await;
    DATABASE.set(db).unwrap();

    let db = DATABASE.get().unwrap();
}

方案2:使用Lazy配合block_on

尝试用Lazy结合block_on直接初始化全局实例,却触发运行时错误:

pub static DATABASE: Lazy<Database> = Lazy::new(|| {
    let pool: Database = Runtime::new()
        .unwrap()
        .block_on(async { Database::init().await });

    pool
});

async fn main() {
    let db = DATABASE.pool;
}

错误信息:

Cannot start a runtime from within a runtime. This happens because a function (like block_on) attempted to block the current thread while the thread is being used to drive asynchronous tasks.

最终实现方案

参考@Chayim Friedman的思路,拆分连接池与结构体的初始化逻辑,实现简洁的全局调用:

修改后的结构体及全局变量定义

#[derive(Debug)]
pub struct Database {
    pub pool: PgPool,
}

impl Database {
    pub fn init() -> Self {
        let pool = POOL.get().unwrap();

        Database { pool: pool.clone() }
    }

    pub async fn create_db_pool() -> PgPool {
        PgPoolOptions::new()
            .max_connections(20)
            .acquire_timeout(Duration::from_secs(3))
            .connect(API_ENV.db_url)
            .await
            .expect("Can't connect to database")
    }
}

pub static DATABASE: Lazy<Database> = Lazy::new(Database::init);
pub static POOL: OnceCell<PgPool> = OnceCell::new();

main函数初始化逻辑

在异步的main中完成连接池的异步初始化:

async fn main() {
    let pool = Database::create_db_pool().await;
    POOL.set(pool).unwrap();
}

全局使用方式

在任意位置直接访问全局DATABASE即可,无需重复unwrap:

fn anywhere() {
    let pool = &DATABASE.pool;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 07:10:04