原創|其它|編輯:郝浩|2009-10-19 10:21:38.000|閱讀 917 次
概述:當前移動設備開發領域,在本地數據存儲方面,Sqlite幾乎成了事實標準,Andriod (android.database.sqlite),iPhone (SQLite for iPhone SDK 和 FMDB for iPhone),Palm WebOS (webOS SQL Tutorial),新版本的Symbian也直接built-in Sqlite了(20 million Symbian smartphones shipped in Q3 2007 Newer versions of the SymbianOS have SQLite built in.)。那么作為移動設備領域的重要一員Windows Mobile怎么可能錯過Sqlite呢。
# 界面/圖表報表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
當前移動設備開發領域,在本地數據存儲方面,Sqlite幾乎成了事實標準,Andriod (),iPhone ( 和 ),Palm WebOS (),新版本的Symbian也直接built-in Sqlite了()。那么作為移動設備領域的重要一員Windows Mobile怎么可能錯過Sqlite呢。
Sqlite幾乎成立移動設備開發領域數據存儲方面的事實標準。Sqlite已經廣泛被使用到Andriod,iPhone,WebOS以及Symbian等平臺了,本文講述在Windows Mobile平臺下如何使用Native C++訪問Sqlite,同時講述一個封裝類的實現和使用。
Sqlite源碼可以到 下載,我為了省事直接使用了的在Windows Mobile下的build工程。
封裝我使用了的封裝。這里感謝的推薦。封裝是對Sqlite原有純C的api進行OO的C++的封裝。主要封裝以下幾個類:
1. CppSQLite3DB 數據庫類,用于新建數據庫,打開關閉鏈接,執行DDL和DML。
2. CppSQLite3Statement 用于執行參數化的SQL。CppSQLite3DB 可以執行SQL但是不支持參數化。
3. CppSQLite3Query 用于讀出執行Select后的查詢結果。
4. CppSQLite3Exception 用于捕捉異常。
簡單明了的封裝了Sqlite。
使用方法源自于我對類的單元測試。見源文件的SqliteHelperTest.h。
TEST(SqliteHelper, CreateDatabase)
{
try
{
CppSQLite3DB db;
DeleteFile(DB_FILE_NAME);
db.open(DB_FILE_NAME);
db.close();
}
catch(CppSQLite3Exception e)
{
FAIL(ToString(e.errorMessage()).c_str());
}
TRACE("Create database successful.");
}
調用CppSQLite3DB 的open()函數的時候如果發現沒有數據庫文件就會新建一個數據庫文件。Sqlite的源代碼如下(見sqlite3.c):
rc = openDatabase(zFilename8, ppDb,
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, 0);
TEST(SqliteHelper, CreateTable)
{
try
{
CppSQLite3DB db;
db.open(DB_FILE_NAME);
db.execDML(L"create table T1(F1 int, F2 char(20), F3 char(20));");
db.close();
}
catch(CppSQLite3Exception e)
{
FAIL(ToString(e.errorMessage()).c_str());
}
TRACE("Create table successful.");
}
執行CppSQLite3DB 的execDML()函數可以執行DDL。Sqlite3的數據類型定義和其他常見關系型數據庫有很大區別,Sqlite3數據類型定義信息是和具體的數據綁定的而不是和字段定義綁定,也就是動態的,同一個字段的不同記錄可以存儲不同的數據類型的數據。所以在定義表的時候定義字段類型不是必須的,具體可以參考 。
TEST(SqliteHelper, InsertTable)
{
try
{
CppSQLite3DB db;
db.open(DB_FILE_NAME);
CString sqlStr;
time_t tmStart, tmEnd;
tmStart = time(0);
for(int i=0; i<max; ++i)
{
SYSTEMTIME currentTime;
GetLocalTime(¤tTime);
sqlStr.Format(L"INSERT INTO T1 (F1, F2, F3) VALUES(%d, 'STR%d', '%d-%d-%d %d:%d:%d')",
i, i, currentTime.wYear, currentTime.wMonth, currentTime.wDay, currentTime.wHour, currentTime.wMinute, currentTime.wSecond);
db.execDML(sqlStr);
}
tmEnd = time(0);
char ch[255];
sprintf(ch, "Insert table successful in %d seconds", tmEnd-tmStart);
TRACE(ch);
db.close();
}
catch(CppSQLite3Exception e)
{
FAIL(ToString(e.errorMessage()).c_str());
}
}
CppSQLite3DB 的execDML()函數不僅可以執行DDL,而且可以執行DML。同理Update和Delete語句一樣。
TEST(SqliteHelper, SelectScalarBeforeInsert)
{
try
{
CppSQLite3DB db;
db.open(DB_FILE_NAME);
int count = db.execScalar(L"SELECT COUNT(*) FROM T1;");
char ch[255];
sprintf(ch, "%d rows in T1 table", count);
TRACE(ch);
db.close();
}
catch(CppSQLite3Exception e)
{
FAIL(ToString(e.errorMessage()).c_str());
}
TRACE("Select scalar before insert successful.");
}
CppSQLite3DB 的execScalar()函數模仿ADO.NET的 用于取第一條記錄的一個字段的值,一般用于聚集函數的查詢。
TEST(SqliteHelper, SelectAfterInsert)
{
try
{
CppSQLite3DB db;
db.open(DB_FILE_NAME);
CppSQLite3Query q = db.execQuery(L"SELECT * FROM T1;");
std::string str;
char ch[255];
while (!q.eof())
{
sprintf(ch, "F1=%d, F2=%S, F3=%S\n", q.getIntField(0), q.getStringField(1), q.getStringField(2));
str += ch;
q.nextRow();
}
TRACE(str.c_str());
db.close();
}
catch(CppSQLite3Exception e)
{
FAIL(ToString(e.errorMessage()).c_str());
}
}
查詢需要借助CppSQLite3Query 來取出查詢的結果。eof()函數判斷是否結束。nextRow()移動到下一條記錄。getIntField()函數和getStringField()函數為讀取當前記錄的特定字段的值。
TEST(SqliteHelper, InsertTableWithTransaction)
{
try
{
CppSQLite3DB db;
db.open(DB_FILE_NAME);
CString sqlStr;
time_t tmStart, tmEnd;
tmStart = time(0);
db.execDML(L"begin transaction;");
for(int i=0; i<max; ++i)
{
SYSTEMTIME currentTime;
GetLocalTime(¤tTime);
sqlStr.Format(L"INSERT INTO T1 (F1, F2, F3) VALUES(%d, 'STR%d', '%d-%d-%d %d:%d:%d')",
i, i, currentTime.wYear, currentTime.wMonth, currentTime.wDay, currentTime.wHour, currentTime.wMinute, currentTime.wSecond);
db.execDML(sqlStr);
}
db.execDML(L"commit transaction;");
tmEnd = time(0);
char ch[255];
sprintf(ch, "Insert table successful in %d seconds", tmEnd-tmStart);
TRACE(ch);
db.close();
}
catch(CppSQLite3Exception e)
{
db.execDML(L"rollback transaction;");
FAIL(ToString(e.errorMessage()).c_str());
}
}
在Sqlite上事務的使用非常簡單。通過CppSQLite3DB 的execDML()函數來打開,提交和回退事務。Sqlite在事務處理上,語法層面上和MS SQL Server有點類似,默認是自動事務(AutoCommit),關于事務處理我之前寫過一篇文章,有興趣可以參考下 。也可以參考
。 從測試結果看,批量處理數據,顯式使用事務和自動事務在處理時間上差別很大。
在insert 100條數據時,顯式使用事務小于1秒鐘完成,而使用自動事務的話需要4秒鐘。為什么有這么大的差別,我沒有仔細研究Sqlite的源碼,我從通用數據庫的概念來講述,事務其中一個特性是持久性(Durability),也就是凡是提交了的事務的數據都需要持久化,需要持久化就需要寫硬盤,在移動設備是flash,寫永久存儲設備的速度是遠遠慢于寫內存的速度的,所以速度差異點在IO。
項目開發中使用了TDD,關于Unit Test可以參考 和 。
本站文章除注明轉載外,均為本站原創或翻譯。歡迎任何形式的轉載,但請務必注明出處、不得修改原文相關鏈接,如果存在內容上的異議請郵件反饋至chenjj@fc6vip.cn
文章轉載自:博客園