手机来电通核心模块——归属地数据库设计(Winsym原创)
?
說到Symbian,確實讓人頭痛。不僅開發平臺和SDK版本眾多,難以選擇,而且對程序員確實要求很高,光是Symbian C++的熟悉就要花上很長時間,更麻煩的是測試和調試。模擬器只能提供一部分功能,和電話通信有關的全部要在真機上測試。很多時候,在模擬器上能跑的代碼,放到真機上就不行了,這其中的心酸想必開發過得朋友深有體會。
小弟我因為工程實踐項目的要求,和幾位嵌入式的高手一起搞了Symbian來電通項目。其實來電通項目已經有很多人做了,比較有名的是CallMaster和柳丁,但是這方面的關鍵技術和源碼至今沒有人公開,這在很大程度上增加了這個項目的難度,我們只好白手起家,也算是一次真正的項目歷練(因為很多項目的關鍵技術和源碼一般都不會給你,只有自己研究,^_^)。我在項目中負責兩個核心模塊的實現。一個是監聽模塊,另一個就是歸屬地查詢模塊。我把這一個多月的成果全部總結了一下,寫成技術文章,提供給大家參考。希望想從事這方面開發的朋友能有一些借鑒作用,少走一些彎路,我就感到非常欣慰了。
以下是最核心的部分,歸屬地數據庫的設計和實現,文中可能存在不少問題,歡迎高手們指正,向Symbian高手學習。
?
說明,我們的開發環境是Carbide C++
SDK?是s60 FP2 CW版
?
?
歸屬地查詢模塊
歸屬地模塊的主要功能可以劃分為兩個部分:一是當監聽模塊獲取號碼后,自動查找歸屬地數據庫;二是由用戶在本地自由查找,可自由選擇組合(手機,固話等歸屬地)。但是兩個功能的核心和難點都在于歸屬地數據庫的建立,下面結合圖例重點闡述。
整個數據庫的建立大致分為三個步驟,見圖示:
?
?
?
?
一、原始數據的采集,整理。這一步驟主要從網上下載我國目前手機號碼的歸屬地數據庫原始數據,我們選用的是access格式的原始數據,但其只有一張表且存在大量冗余信息,原始數據截圖如下:
?
?二、對原始數據進行分析和總結不難看出,city和cardtype字段中存在大量冗余信息。例如:北京市和北京聯通GSM卡被存取了很多次,造成了大量的重復。所以,我們必須要設計出一種優秀的表結構格式(在滿足功能的前提下,最大限度地消除冗余信息,采用數據庫設計相關理論,達到3范式設計要求)。共設計四張表:
1 Phone
2 CityName
3 CardName
4 Zone
?
具體字段如下:
??
?
|
表名 |
字段名 |
類型 |
長度 |
說明 |
|
Phone |
number |
?????int |
? |
手機號碼段,主碼唯一標示 |
|
? |
cityid |
??int |
? |
歸屬城市編號 |
|
? |
cardid |
??int |
? |
卡類型編號 |
|
CityName |
cityid |
int |
? |
歸屬城市編號,主碼 |
|
? |
cityname |
text |
50 |
歸屬城市名稱 |
|
CardName |
cardid |
int |
? |
卡類型編號,主碼 |
|
? |
cardname |
text |
50 |
卡類型名稱 |
|
Zone |
zonecode |
text |
10 |
二級城市歸屬地區號?聯合主碼 |
|
? |
zonename |
text |
50 |
二級城市歸屬地名稱 聯合主碼 |
?
?
在實際應用過程中,查找效率和安全問題是我們必須要考慮的兩個主要問題,為此我們采取了以下解決方案:
對于查找效率問題,我們采用了建立索引機制。由于Phone表中的記錄的規模(大約有15萬條記錄),為了提高查找效率,對表Phone中的字段number,CityName的cityid字段,CardName的cardid字段分別建立索引。相應Sql語句可參考以下:
CREATE unique INDEX numIndex ON Phone(number)
CREATE unique INDEX cardidIndex ON CardName(cardid)
CREATE unique INDEX cityidIndex ON CityName(cityid)
?
對于安全問題,我們使用了S60 2nd?DBMS專有的權限加密機制,相當于SQL Server數據庫的登錄密碼,最大限度的保護數據庫訪問的安全和數據庫設計專利。具體實現可參考以下代碼片段:
// Open the contacts database using the Encrypted format
????_LIT(KPassword, "I Fu le you");
????//useing decrypted database
????CSecurityBase* securityBase = Security::NewL ();
????securityBase->SetL?(TPtrC?(), KPassword);?//Set the password for decryption
????//Get the key
????CSecurityDecryptBase* decryptBase = securityBase->NewDecryptL (TPtrC8 ());
????CleanupStack::PushL (securityBase);
????User::LeaveIfError?( myDatabase.Open?(myDbs, KFile,?TPtrC?(), decryptBase,myDatabase.EReadOnly));
?
為了方便Sql腳本的提取,以上設計均在SqlServer2000數據庫中完全實現。四張表之間的關系可參考以下截圖:
?
?
?
三、最后一步是將SqlServer2000平臺上的歸屬地數據庫順利地導入到Symbian專用的?DBMS中。這里存在兩個難點,一是Symbian數據庫的建立,API的使用;二是海量數據的導入。
對于第一個問題,Symbian為我們提供了兩組API:
1.?RDbStoreDatabase?提供了專有的創建和打開數據庫的接口,這樣的數據庫是不能共享的,數據庫以文件的形式存在,所以它又稱為客戶端訪問。
2.?RDbNamedDatabase?提供了用名字和格式標識的創建和打開數據庫的接口,這個類允許客戶端(專有)和服務的共享數據庫訪問。
考慮到程序的兼容和開發的方便,我們使用的是RDbNamedDatabase,他可以輕松地創建我們想要的數據庫,并利用Symbian支持的SQL子集,進行相應的建表,建立索引,查詢等操作,完成相應功能需求。代碼片段如下:
RFs?myDbs;
????// handle for our database
????RDbNamedDatabase?myDatabase;
????// we have to connect to the DBMS server first
????User::LeaveIfError( myDbs.Connect());
????myDbs.MkDirAll(KDirName);
????//handles use the cleanup stack
????CleanupClosePushL(myDbs);
????_LIT(KPassword, "I Fu le you");
????//useing encrypted database
????CSecurityBase* securityBase = Security::NewL();
????securityBase->SetL(TPtrC(), KPassword);?//Set the password for encryption
?
????// Get the key
????CSecurityEncryptBase* encryptBase = securityBase->NewEncryptL(TPtrC8());
???
????User::LeaveIfError( myDatabase.Create(myDbs,KFile,TPtrC(),encryptBase));
????//handles use the cleanup stack
????CleanupClosePushL(myDatabase);
???
????_LIT(KSQLCreatePhone, "CREATE TABLE Phone(number??integer ,cityid??unsigned smallint,cardid??unsigned smallint)");
????_LIT(KSQLIndex,"CREATE unique INDEX numIndex ON Phone(number) ");
????_LIT(KSQLIndex1,"CREATE unique INDEX cardidIndex ON CardName(cardid) ");
????_LIT(KSQLIndex2,"CREATE unique INDEX cityidIndex ON CityName(cityid) ");
???
????_LIT(KSQLCreateCardName,"Create Table CardName(cardid unsigned smallint,cardtype varchar)");
????_LIT(KSQLCreateCityName,"Create Table CityName(cityid unsigned smallint,cityname varchar)");
????_LIT(KSQLCreateZone,"Create Table Zone(zonecode varchar,zonename varchar)");
???
????//create Master tables
????User::LeaveIfError(myDatabase.Execute(KSQLCreatePhone));
????User::LeaveIfError(myDatabase.Execute(KSQLCreateCardName));
????User::LeaveIfError(myDatabase.Execute(KSQLCreateCityName));
????User::LeaveIfError(myDatabase.Execute(KSQLCreateZone));
?
????User::LeaveIfError(myDatabase.Execute(KSQLIndex));
????User::LeaveIfError(myDatabase.Execute(KSQLIndex1));
????User::LeaveIfError(myDatabase.Execute(KSQLIndex2));
?
對于第二個問題,我們采取的方法是,將所有Sql Server2000數據庫各表格的數據,全部轉成sql腳本,并利用Symbian提供的文件系統相關的API,讀取每一行sql語句并執行,最終在電腦模擬器上生成數據庫文件dbms.db。經實際操作,這種方法比在手機上生成可以大大節省數據庫生成時間,效果顯著。相應的sql腳本截圖如下:
?
?
?
讀取的代碼片段如下:
RFile?myfile;
????//open file with RFile
????User::LeaveIfError(myfile.Open(myDbs,KFileName1,EFileRead));
????CleanupClosePushL(myfile);
???
????//Reads??single lines of text to or from a file
????txt.Set(myfile);
????TBuf16<60>?textsql;
????//TDesC16 sqlRow;
????while(txt.Read(textsql) != KErrEof??)
????{
???????//console->Printf(textsql);
???????User::LeaveIfError(myDatabase.Execute(textsql));
???????//console->Printf(_L("/n"));
???????textsql.Delete(0,textsql.Length());
????}
全部完成后,就可以利用SQL語句查詢了,哈哈,好爽啊!
?
總結
以上是生活随笔為你收集整理的手机来电通核心模块——归属地数据库设计(Winsym原创)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 归并排序 自带时间复杂度测试
- 下一篇: 年轻人倡导“数字排毒”,美国功能手机市场