最近又測試了一下記憶體資料庫SQLite,發現功能增強了好多,比如多線程支援(用檔案鎖的方式實現的),並且也可以全記憶體化(用":memory:"的方式開啟即可)了。
由於多線程的支援是通過作業系統檔案鎖的方式實現的,所以當以全記憶體資料庫(即無磁碟檔案)的方式開啟SQLite時,就不支援多線程了,必須自行實現讀寫鎖以互斥,推薦使用ACE讀寫鎖。
由於SQLite的鎖是檔案鎖的方式實現,所以它不能實現表級鎖,而只能是全資料庫檔案鎖。另外,線程間不能以共用資料庫指標的方式實現共用,而要分別開啟一個SQLite執行個體,互斥機制才能正確的工作。所以,如果你使用":memory:"的方式開啟SQLite,不同線程之間很難共用一個資料庫(每一個線程都開啟了一個全新的執行個體),如果你簡單的通過指標來共用,又會造成互斥機制不能正常工作,這個矛盾我還沒有找到解決辦法。
經過測試,發現SQLite和自己實現的資料結構(比如STL)的效能還是有一定差距,比如我遍曆一個query的結果集的時間通常在幾十毫秒(時間主要和記錄集大小有關,幾十毫秒是幾十到幾百條記錄的結果),不過考慮到方便的儲存和實現索引﹑事務等功能,這個開銷還是值得的。
使用時注意如果你要使用顯示事務(預設的DML語句操作使用autocommit模式),要自行控制重試,而不能像一般的網路資料庫那樣,由資料庫連接進行阻塞等待,SQLite在你申請事務時會直接返回,不管成功與否;但你可以用下面的方法自行控制:
- int iRet;
- do
- {
- iRet = CppSQLite3DB::exeDML("begin IMMEDIATE;");
- if (iRet == SQLITE_BUSY)
- Sleep(20);
- } while(iRet == SQLITE_BUSY);
測試時,我用到了幾個CodeProject網站上發表的封裝類:
1)ODBC的封裝類CODBCDatabase,CODBCRecordset
2)SQLite的封裝類CppSQLite
3)對象池的封裝類PoolMgr
這些類都是比較好的封裝類,可以輕易地整合進自己的應用。我還特地實現了幾個直接通過ODBC把網路資料庫的內容轉到SQLite的通用函數,這樣,可以輕易地進行本地應用的資料初始化(特別當這些初始資料來自於網路資料庫時),還可以用幾句話就為這些資料建立合適的索引,起到真正的記憶體資料庫的作用。