手机来电通核心模块——归属地数据库设计(Winsym原创)
?
說到Symbian,確實(shí)讓人頭痛。不僅開發(fā)平臺(tái)和SDK版本眾多,難以選擇,而且對(duì)程序員確實(shí)要求很高,光是Symbian C++的熟悉就要花上很長(zhǎng)時(shí)間,更麻煩的是測(cè)試和調(diào)試。模擬器只能提供一部分功能,和電話通信有關(guān)的全部要在真機(jī)上測(cè)試。很多時(shí)候,在模擬器上能跑的代碼,放到真機(jī)上就不行了,這其中的心酸想必開發(fā)過得朋友深有體會(huì)。
小弟我因?yàn)楣こ虒?shí)踐項(xiàng)目的要求,和幾位嵌入式的高手一起搞了Symbian來電通項(xiàng)目。其實(shí)來電通項(xiàng)目已經(jīng)有很多人做了,比較有名的是CallMaster和柳丁,但是這方面的關(guān)鍵技術(shù)和源碼至今沒有人公開,這在很大程度上增加了這個(gè)項(xiàng)目的難度,我們只好白手起家,也算是一次真正的項(xiàng)目歷練(因?yàn)楹芏囗?xiàng)目的關(guān)鍵技術(shù)和源碼一般都不會(huì)給你,只有自己研究,^_^)。我在項(xiàng)目中負(fù)責(zé)兩個(gè)核心模塊的實(shí)現(xiàn)。一個(gè)是監(jiān)聽模塊,另一個(gè)就是歸屬地查詢模塊。我把這一個(gè)多月的成果全部總結(jié)了一下,寫成技術(shù)文章,提供給大家參考。希望想從事這方面開發(fā)的朋友能有一些借鑒作用,少走一些彎路,我就感到非常欣慰了。
以下是最核心的部分,歸屬地?cái)?shù)據(jù)庫(kù)的設(shè)計(jì)和實(shí)現(xiàn),文中可能存在不少問題,歡迎高手們指正,向Symbian高手學(xué)習(xí)。
?
說明,我們的開發(fā)環(huán)境是Carbide C++
SDK?是s60 FP2 CW版
?
?
歸屬地查詢模塊
歸屬地模塊的主要功能可以劃分為兩個(gè)部分:一是當(dāng)監(jiān)聽模塊獲取號(hào)碼后,自動(dòng)查找歸屬地?cái)?shù)據(jù)庫(kù);二是由用戶在本地自由查找,可自由選擇組合(手機(jī),固話等歸屬地)。但是兩個(gè)功能的核心和難點(diǎn)都在于歸屬地?cái)?shù)據(jù)庫(kù)的建立,下面結(jié)合圖例重點(diǎn)闡述。
整個(gè)數(shù)據(jù)庫(kù)的建立大致分為三個(gè)步驟,見圖示:
?
?
?
?
一、原始數(shù)據(jù)的采集,整理。這一步驟主要從網(wǎng)上下載我國(guó)目前手機(jī)號(hào)碼的歸屬地?cái)?shù)據(jù)庫(kù)原始數(shù)據(jù),我們選用的是access格式的原始數(shù)據(jù),但其只有一張表且存在大量冗余信息,原始數(shù)據(jù)截圖如下:
?
?二、對(duì)原始數(shù)據(jù)進(jìn)行分析和總結(jié)不難看出,city和cardtype字段中存在大量冗余信息。例如:北京市和北京聯(lián)通GSM卡被存取了很多次,造成了大量的重復(fù)。所以,我們必須要設(shè)計(jì)出一種優(yōu)秀的表結(jié)構(gòu)格式(在滿足功能的前提下,最大限度地消除冗余信息,采用數(shù)據(jù)庫(kù)設(shè)計(jì)相關(guān)理論,達(dá)到3范式設(shè)計(jì)要求)。共設(shè)計(jì)四張表:
1 Phone
2 CityName
3 CardName
4 Zone
?
具體字段如下:
??
?
|
表名 |
字段名 |
類型 |
長(zhǎng)度 |
說明 |
|
Phone |
number |
?????int |
? |
手機(jī)號(hào)碼段,主碼唯一標(biāo)示 |
|
? |
cityid |
??int |
? |
歸屬城市編號(hào) |
|
? |
cardid |
??int |
? |
卡類型編號(hào) |
|
CityName |
cityid |
int |
? |
歸屬城市編號(hào),主碼 |
|
? |
cityname |
text |
50 |
歸屬城市名稱 |
|
CardName |
cardid |
int |
? |
卡類型編號(hào),主碼 |
|
? |
cardname |
text |
50 |
卡類型名稱 |
|
Zone |
zonecode |
text |
10 |
二級(jí)城市歸屬地區(qū)號(hào)?聯(lián)合主碼 |
|
? |
zonename |
text |
50 |
二級(jí)城市歸屬地名稱 聯(lián)合主碼 |
?
?
在實(shí)際應(yīng)用過程中,查找效率和安全問題是我們必須要考慮的兩個(gè)主要問題,為此我們采取了以下解決方案:
對(duì)于查找效率問題,我們采用了建立索引機(jī)制。由于Phone表中的記錄的規(guī)模(大約有15萬(wàn)條記錄),為了提高查找效率,對(duì)表Phone中的字段number,CityName的cityid字段,CardName的cardid字段分別建立索引。相應(yīng)Sql語(yǔ)句可參考以下:
CREATE unique INDEX numIndex ON Phone(number)
CREATE unique INDEX cardidIndex ON CardName(cardid)
CREATE unique INDEX cityidIndex ON CityName(cityid)
?
對(duì)于安全問題,我們使用了S60 2nd?DBMS專有的權(quán)限加密機(jī)制,相當(dāng)于SQL Server數(shù)據(jù)庫(kù)的登錄密碼,最大限度的保護(hù)數(shù)據(jù)庫(kù)訪問的安全和數(shù)據(jù)庫(kù)設(shè)計(jì)專利。具體實(shí)現(xiàn)可參考以下代碼片段:
// 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腳本的提取,以上設(shè)計(jì)均在SqlServer2000數(shù)據(jù)庫(kù)中完全實(shí)現(xiàn)。四張表之間的關(guān)系可參考以下截圖:
?
?
?
三、最后一步是將SqlServer2000平臺(tái)上的歸屬地?cái)?shù)據(jù)庫(kù)順利地導(dǎo)入到Symbian專用的?DBMS中。這里存在兩個(gè)難點(diǎn),一是Symbian數(shù)據(jù)庫(kù)的建立,API的使用;二是海量數(shù)據(jù)的導(dǎo)入。
對(duì)于第一個(gè)問題,Symbian為我們提供了兩組API:
1.?RDbStoreDatabase?提供了專有的創(chuàng)建和打開數(shù)據(jù)庫(kù)的接口,這樣的數(shù)據(jù)庫(kù)是不能共享的,數(shù)據(jù)庫(kù)以文件的形式存在,所以它又稱為客戶端訪問。
2.?RDbNamedDatabase?提供了用名字和格式標(biāo)識(shí)的創(chuàng)建和打開數(shù)據(jù)庫(kù)的接口,這個(gè)類允許客戶端(專有)和服務(wù)的共享數(shù)據(jù)庫(kù)訪問。
考慮到程序的兼容和開發(fā)的方便,我們使用的是RDbNamedDatabase,他可以輕松地創(chuàng)建我們想要的數(shù)據(jù)庫(kù),并利用Symbian支持的SQL子集,進(jìn)行相應(yīng)的建表,建立索引,查詢等操作,完成相應(yīng)功能需求。代碼片段如下:
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));
?
對(duì)于第二個(gè)問題,我們采取的方法是,將所有Sql Server2000數(shù)據(jù)庫(kù)各表格的數(shù)據(jù),全部轉(zhuǎn)成sql腳本,并利用Symbian提供的文件系統(tǒng)相關(guān)的API,讀取每一行sql語(yǔ)句并執(zhí)行,最終在電腦模擬器上生成數(shù)據(jù)庫(kù)文件dbms.db。經(jīng)實(shí)際操作,這種方法比在手機(jī)上生成可以大大節(jié)省數(shù)據(jù)庫(kù)生成時(shí)間,效果顯著。相應(yīng)的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語(yǔ)句查詢了,哈哈,好爽啊!
?
總結(jié)
以上是生活随笔為你收集整理的手机来电通核心模块——归属地数据库设计(Winsym原创)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 归并排序 自带时间复杂度测试
- 下一篇: 年轻人倡导“数字排毒”,美国功能手机市场