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
相关产品推荐
相关产品推荐

