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

Rust中使用mysql crate存储缓存预编译语句的最佳实践

Rust中使用mysql crate存储预编译语句的最佳实践

我正在开发一个基于MySQL的Rust小型Web服务器作为学习项目,想了解使用mysql crate存储预编译语句的最佳实践。

我有Java学术背景,在Java里会这么实现:

首先定义静态PreparedStatement:

private static PreparedStatement SOME_STATEMENT; 

随后在数据库初始化时创建语句:

SOME_STATEMENT = conn.prepareStatement("SELECT COUNT(Distinct SOME_FIELD) FROM SOME_TABLE");

最后通过同步静态方法封装执行逻辑:

public synchronized static int someDatabaseQuery()  throws SQLException{
    try (ResultSet results = SOME_STATEMENT.executeQuery()) {
      results.next();
      return results.getInt(1);
    }
}

由于Java允许一些Rust视为"unsafe"的操作,这种实现方式相对简单。我想知道不依赖Lazy static等外部库的情况下,Rust的最佳实现方式是什么?

我目前的思路是定义如下Database结构体:

pub struct Database {
    url: String,
    pool: Pool,
    conn: PooledConn,
    stmtOne: Stmt, 
    .... // more statements
}

并通过new方法初始化结构体:

pub fn new(
    database_username: &String,
    password: &String,
    database_url: &String,
    database_name: &String,
) -> Result<Database, Box<dyn Error>> {
    let url = format!(
        "mysql://{}:{}@{}/{}",
        database_username, password, database_url, database_name
    );

    let opts = Opts::from_url(url.as_str())?;
    let pool = Pool::new(opts)?;

    let mut conn = match pool.get_conn() {
        Ok(conn) => conn,
        Err(err) => return Err(Box::new(err)),
    };

    let mut stmtOne = conn.prep("").unwrap();
    ...// more initiations 

    Ok(Database {
        url,
        pool,
        conn,
        stmtOne,
        ... // more statements
    })
}

但我觉得这种方式十分繁琐,相信Rust有更优的实现方式,请问最佳方案是什么?


解决方案

根据建议,实现方式如下:

首先定义Database结构体:

pub struct Database {
    url: String,
    pool: Pool,
    conn: PooledConn,
}

使用OnceLock声明静态语句:

static SOME_STATEMENT: OnceLock<Statement> = OnceLock::new();
static SOME_STATEMENT_TWO: OnceLock<Statement> = OnceLock::new();

调整初始化方法以创建静态语句:

pub fn new(
    database_username: &String,
    password: &String,
    database_url: &String,
    database_name: &String,
) -> Database {
    let url = format!(
        "mysql://{}:{}@{}/{}",
        database_username, password, database_url, database_name
    );

    let opts = Opts::from_url(url.as_str()).unwrap();
    let pool = Pool::new(opts).unwrap();

    match pool.get_conn() {
        Ok(mut conn) => {
            SOME_STATEMENT.get_or_init(|| conn.prep(" SELECT USERNAME FROM SOME_TABLE WHERE USERNAME=:username").unwrap());
            SOME_STATEMENT_TWO.get_or_init(|| conn.prep(" ... some other query").unwrap());
            return Database { url, pool, conn };
        }
        Err(err) => panic!("Unable to initialize database: {err}"),
    };
}

最后在方法中调用静态语句:

pub fn some_database_query(&mut self, name: &String) -> Option<Vec<String>> {
    match SOME_STATEMENT.get() {
        Some(stmt) => Some(self.conn.exec(stmt, params! {"username" => name}).unwrap()),
        None => None,
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 05:45:40