如何存储SQLite准备好的语句供以后使用?

ben*_*ben 5 sqlite rust

现在我有代码使用rusqlitesqlite绑定打开数据库连接并在我的应用程序中执行一堆数据库操作,如下所示:

extern crate rusqlite;

use rusqlite::SqliteConnection;

struct MyAppState {
    db: SqliteConnection,
    // ... pretend there's other fields here ...
}

impl MyAppState {
    fn new() -> MyAppState {
        let db = SqliteConnection::open(":memory:").unwrap();
        MyAppState {
            db: db
        }
    }

    fn query_some_info(&mut self, arg: i64) -> i64 {
        let mut stmt = self.db.prepare("SELECT ? + 1").unwrap();
        let mut result_iter = stmt.query(&[&arg]).unwrap();
        let result = result_iter.next().unwrap().unwrap().get(0);

        result
    }
}

fn main() {
    let mut app = MyAppState::new();
    for i in range(0, 100) {
        let result = app.query_some_info(i);
        println!("{}", result);
    }
}
Run Code Online (Sandbox Code Playgroud)

由于准备好的语句存在于局部变量中,这似乎在某种程度上忽略了准备语句的要点,因为每次调用函数并且局部变量产生时我必须重新准备它.理想情况下,我最多只准备一次所有语句,并MyAppState在数据库连接期间将它们存储在结构中.

但是,由于SqliteStatement类型是在db连接的生命周期中参数化的,它借用了连接和扩展它所在的结构,我不再对结构做任何事情,比如返回struct by value或者调用&mut self它上面的方法(query_some_info并不真的需要&mut self这里,但在我的实际程序的一些代码做,除非一切都对住在RefCells,这还不是最糟糕的,我猜,但仍然).

通常当借用检查员背叛我这样的时候,我的办法就是放弃堆栈纪律,把Rc<RefCell< >>它放在一起,直到一切都解决了,但在这种情况下,在这种情况下有一些生命周期类型,我不知道如何用借口检查者的方式来说出来.

理想情况下,我想编写的代码只在db打开时才准备好语句,或者在第一次使用时只准备一次,然后prepare在db连接期间再也不会调用,同时主要是保持安全性rusqlite绑定,而不是针对sqlite3 C API编写代码或破坏抽象等等.我如何能?

Mat*_* M. 4

事实上,你是对的,同级引用在 Rust 中很尴尬。不过,有一个很好的理由,即它们不容易通过所有权制度建模。

在这种特殊情况下,我建议您拆分结构:您可以将准备好的语句保存在专用缓存中,该缓存db根据例如的生命周期进行参数化;相反db,应该在程序的顶部实例化并向下传递(考虑依赖注入),以便依赖于它的缓存可以比程序主函数的寿命更长。

显然,这确实意味着遗嘱db仍然是借用的。