2014-12-18 106 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

你能提供一個這個想法的例子嗎? –