2014-12-18 110 views
4

现在我有一个使用rusqlite sqlite bindings在我的应用程序打开一个数据库连接,并做了一堆数据库操作的这样的代码:如何存储SQLite准备好的语句供以后使用?

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); 
    } 
} 

由于事先准备好的声明生活在一个局部变量,这似乎错过在某种程度上准备好的陈述的重点,因为每次函数被调用并且局部变量出现时我都必须重新准备它。理想情况下,我会最多准备一次我的语句,并在db连接期间将它们存储在MyAppState结构中。

然而,由于SqliteStatement type is parameterized over the lifetime of the db connection,它借用了连接,并推而广之的结构它生活在,我不能做的结构什么了类似的值返回结构或调用它的&mut self方法(query_some_info不真的需要在这里采取&mut self,但我的实际计划中的一些代码确实如此,除非所有事情都继续生活在RefCell之间,但我认为这并不是最差的)。

通常,当借阅检查员背叛我时,我的追求是放弃堆栈管理,并在其中放置一些Rc<RefCell< >>,直到全部解决为止,但在这种情况下,这些类型中存在一些生命周期,不知道如何以一种安抚借用检查器的方式来表达它。

理想情况下,我想编写代码,只有在数据库打开时才准备语句,或者在第一次使用时只准备一次,然后在数据库连接期间再次不调用prepare,同时主要保持rusqlite绑定的安全性,而不是针对sqlite3 C API编写代码或打破抽象或其他任何操作。我如何?

回答

4

你是对的的确,兄弟姐妹的引用在Rust里很尴尬。然而,有一个很好的理由,它们不容易被所有权系统模拟​​。

在这种特殊情况下,我建议你分裂结构:你可以保持准备语句在专用高速缓存参数化的db例如寿命;而应该在程序的顶部实例化db,并传递(认为依赖注入),以便依赖于它的缓存可以超出程序主函数。

这确实意味着db将保持借用,显然。

+0

你能提供一个这个想法的例子吗? –