S60DBMSAPIs.docx
《S60DBMSAPIs.docx》由会员分享,可在线阅读,更多相关《S60DBMSAPIs.docx(26页珍藏版)》请在冰豆网上搜索。
S60DBMSAPIs
S60_DBMS_APIs
symbian2010-06-0909:
45:
46阅读80评论0字号:
大中小
1.Introduction
2.DBMSstructureandelements
2.1Permanentfilestoresandstreams
2.2Createadatabase
2.3Definetableswithinadatabase
2.3.1Columns
2.3.2Columnsets
2.3.3Indexkeys
2.4Queryschemainformation
2.5Openandcloseadatabase
2.6Createdata
2.6.1Longcolumndatainadatabase
3.UsingRowSetsandcursors
3.1RowSetdefinition
3.1.1RowSetbase
3.1.2TableRowSets
3.1.3SQLviews
3.2Cursors
3.2.1Cursorstates
3.3Retrievingdatabyindex
4.UsingSQLwithDBMS
4.1SQLandthenativeC++API
4.2BreakdownofaSelectstatement
4.3SupportedSQLsubset
4.4UsingTDbQueryclass
4.5SQLschemaanddataupdates
4.5.1DatabaseDefinitionLanguage(DDL)
4.5.2SQLdataupdatestatements(DML)
4.5.3Examples
5.Incrementaldatabaseoperations
5.1Overview
5.2Databaseincrementaloperations—RDbIncremental
5.3DMLstatementincrementalexecution—RDbUpdate
5.3.1DMLsynchronous
5.3.2DMLasynchronous
6.Sharingdatabases
6.1DBMSserversession
6.2Databasechangenotifier
6.3Transactionsandlocks
1.介绍
这篇文档介绍了SymbianOS中怎样有效使用关系数据库API,即DBMSAPI。
SymbianOS提供了创建和维护数据库的功能,并实现了通过本地和SQL可靠安全访问数据库的方法。
SQL调用支持事务和回滚机制,这就保证了数据全写或全部未写。
2.数据库结构和元素
SymbianOSDBMS提供了一个关系数据库的功能接口。
所有SymbianOSDBMS都具有一个元素层次:
最顶端的是包含数据库的文件存储,它包含表。
表是由列定义的,由行组成的。
列是由数据类型和长度定义的,DBMS支持一个丰富的数据类型。
开发者过去使用的非DBMS数据库环境,比如ISAM,行可以被认为是记录,列类似域。
但是,需要指出的是,在DBMS中,行和列都具有除了记录和域之外的其他属性。
SymbianOSDBMS是一个功能强大的,轻量级的实现,它支持使用SQL,DDL(DataDefinitionLanguage),DML(DataModelingLanguage)进行常用的增加、查询、获取、更新和删除操作。
尽管是轻量级,SymbianOSDBMS给手持设备使用者提供了适用的功能,数据库大小也仅仅局限于可用资源。
2.1永久性文件存储和流
SymbianOSDBMS依赖文件服务器,永久文件存储和流的实现。
在SymbianOS中,文件存储和流是非常相近的。
通常理解,文件存储字面意义上讲,就是磁盘上的文件,一个文件在目录列表中拥有一个可见的名字。
但是文件的实现决定了它的内容和意图并不能在“视图”中表示。
流是典型的向/从一个存储进行内化/外化的对象,一个存储可以理解成流的集合。
永久文件存储实现了一种典型类型,它当中的流可以被个别改变,而不是使用其他存储类型一次性替换。
网络对象包含的应用程序数据被结构化,以便是数据修改时可以加载或写入,RAM经常是用以改变的媒介。
永久文件存储使用类CPermanentFileStore,它继承自CFileStore,这些类在文件存储API中定义。
这种存储实现了存储虚框架中大部分功能,最重要的是,永久存储中的流可以:
*预先被创建
*重写
*替换
*删除
2.2创建数据库
有两个API可以用来创建数据库:
1.RDbStoreDatabase提供了专有的创建和打开数据库的接口,这样的数据库是不能共享的,数据库以文件的形式存在,所以它又称为客户端访问。
2.RDbNameDatabase提供了用名字和格式标识的创建和打开数据库的接口,这个类允许客户端(专有)和服务的共享数据库访问。
不管是哪种数据库,数据库都是建立在文件上的。
在创建阶段,两种API都需要以专有模式使用RFs文件服务器会话,如果数据库需要被共享,就必须使用RDbNameDatabase来创建和关闭数据库,最后使用数据库服务器会话类RDbs来打开数据库。
在使用数据库时,首选RDbNameDatabase。
使用RDbStoreDatabase创建数据库
classCBookDb:
publicCBase
{
...
private:
//Memberdata
RFsiFsSession;
RDbStoreDatabaseiBookDb;
CFileStore*iFileStore;
...
};
TIntCBookDb:
:
CreateDb(constTFileName&aNewBookFile)
{
Close();
//Createemptydatabasefile.
TRAPD(error,
iFileStore=CPermanentFileStore:
:
ReplaceL(iFsSession,
aNewBookFile,EFileRead|EFileWrite);
iFileStore->SetTypeL(iFileStore->Layout());//Setfilestoretype
TStreamIdid=iBookDb.CreateL(iFileStore);//Createstreamobject
iFileStore->SetRootL(id);//KeepdatabaseIDasrootofstore
iFileStore->CommitL();//Completecreationbycommitting
//CreateBooktablesandindexes
CreateBooksTableL();
CreateBooksIndexL();
);
使用RDbNameDatabase创建数据库
使用RDbNameDatabase创建数据库更简单,因为无需使用流。
...
RFsiFsSession;
RDbNamedDatabaseiBookDb;
...
TIntCBookDb:
:
CreateDb(constTFileName&aNewBookFile)
{
Close();
TInterror=iBookDb.Replace(iFsSession,aNewBookFile);
if(error!
=KErrNone)
{
returnerror;
}
...//Databaseisnowopen.Createtablesetc.
}
Replace方法创建一个新数据库或替换现有数据库,它会将数据库文件置空,然后数据库就是打开状态,并为后面的建表做好了准备。
注意,通过创建数据库,现在的访问模式是专有的。
Replace方法中的TFileName为文件全称(包含路径)。
在SymbianOSDBMS中,数据库名字长度被限制为不超过64个字符。
数据库名字跟文件名字相对应,这取决于程序员是否在文件上使用扩展名,下面是几个合法的名字:
_LIT(KDbName,"C:
\\system\\apps\\DBMS\\DBMS.dat");
_LIT(KDbName,"C:
\\system\\apps\\DBMS\\DBMS");
在S60第三版上的合法路径和名字:
Applicationprivatepath:
_LIT(KDbName,"C:
\\Private\\\\DBMS.dat");
_LIT(KDbName,"C:
\\Private\\\\DBMS");
Publicpath(e.g.):
_LIT(KDbName,"C:
\\Data\\\\DBMS.dat");
_LIT(KDbName,"C:
\\Data\\\\DBMS");
2.3在数据库中创建表
要定义表结构,开发者需要了解三个关键的API概念:
列(column),列集(columnset)和索引键(indexkey)。
数据库中的表必须名字唯一,表中的列名也必须唯一,表和列名都是大小写敏感的。
列
数据库中的表是由一系列“列”定义而成的,每个列都具有名字,类型等属性,如果是文本或二进制,还具有最大长度的属性。
与列对于的类是TDbCol。
列集
描述表的列的集合使用类CDbColSet。
TDbColSetter()可以用来遍历整个列集。
下面的代码片段示例了如何在永久文件存储中建立数据库表结构。
...
constintKTitleMaxLength=60;
_LIT(KBooksTable,"Books");
_LIT(KBooksAuthorCol,"Author");
_LIT(KBooksTitleCol,"Title");
_LIT(KBooksDescriptionCol,"Description");
...
//SpecifycolumnsforBookstable
TDbColauthorCol(KBooksAuthorCol,EDbColText);//Defaultlength
TDbColtitleCol(KBooksTitleCol,EDbColText,KTitleMaxLength);
titleCol.iAttributes=TDbCol:
:
ENotNull;
//StreamData
TDbColdescriptionCol(KBooksDescriptionCol,EDbColLongText);
//Createcolumnset
CDbColSet*bookColSet=CDbColSet:
:
NewLC();
bookColSet->AddL(authorCol);
bookColSet->AddL(titleCol);
bookColSet->AddL(descriptionCol);
//CreatetheBookstable
User:
:
LeaveIfError(iBookDb.CreateTable(KBooksTable,
*bookColSet));
CleanupStack:
:
PopAndDestroy(bookColSet);
...
首先,使用宏_LIT定义列的名字,然后定义列,并将他们Add到bookColSet中。
示例代码中提供了文本域的默认长度和自定义长度,其中默认长度为50。
对于titleCol列,将它的成员iAttributes赋值为ENotNull,这样就强制表中每个row的titleCol都必须赋值。
索引键
索引键需要一个或多个表列,每个键都具有一些属性,例如唯一性,文本列的比较规范,生成键的列。
如果没有索引键定义,表中的行的顺序是任意的。
索引键对应的类是CDbKey,键对应的列对应的类是TDbKeyCol。
s
下面的代码片段示例了在一个表中建立两个列索引的过程。
...
_LIT(KBooksTable,"Books");
_LIT(KBooksAuthorCol,"Author");
_LIT(KBooksTitleCol,"Title");
_LIT(KBooksIndexName,"BooksIndex");
...
//Createindexconsistingoftwocolumns
TDbKeyColauthorCol(KBooksAuthorCol);
TDbKeyColtitleCol(KBooksTitleCol);
CDbKey*index=CDbKey:
:
NewLC();//createindexkeyset
index->AddL(titleCol);
index->AddL(authorCol);
User:
:
LeaveIfError(iBookDb.CreateIndex(
KBooksIndexName,KBooksTable,*index));
CleanupStack:
:
PopAndDestroy(index);
首先,指定用于创建索引的列,然后定义CDbKey对象,并将列Add,最后使用数据库的CreatIndex()来创建索引。
查询模式信息
有API来查询数据库结构,比如索引,表结构等。
数据库的基类RDbDatabase提供了一些基本方法。
*TableNamesL()得到数据库中所有表的名字,返回CDbTableNames。
*IndexNamesL()得到一个表所有索引的名字,返回CDbIndexNames,需要表名做参数。
*ColSetL()得的一个表的所有列,返回CDbColSet,需要表名做参数。
*KeyL()对一个表的索引进行索引定义,需要表名和索引名作为参数。
表的列集CDbColSet可以使用查询语句从表中或SQL视图中获得,列集CDbColSet可以使用TDbColSetIter类作为游标。
下面的示例代码演示了如何获取表的列名和大小,得到的结果放在CDesCArrayFlat中。
...
private:
//Memberdata
RDbStoreDatabaseiBookDb;
...
//Itemsinthearrayareinformat:
CDesCArrayFlat*CBookDb:
:
ColumnNamesAndSizesL()
{
RDbTablebooksTable;
TBufcolumnNameAndSize;
_LIT(KDelimiter,":
");
_LIT(KNoSize,"Nosize");
//OpentheBookstable.
User:
:
LeaveIfError(
booksTable.Open(iBookDb,KBooksTable,booksTable.EReadOnly));
CleanupClosePushL(booksTable);//Remembertopopandclose
CDesCArrayFlat*resultArray=new(ELeave)CDesC16ArrayFlat(KArrayGranularity);
CleanupStack:
:
PushL(resultArray);
//IteratethroughthecolumnsofBookstable.Extractthe
//columnnameandcolumnsize(sizeonlyfortextcolumns).
CDbColSet*colSet=booksTable.ColSetL();
CleanupStack:
:
PushL(colSet);
TDbColSetItercolIter(*colSet);
while(colIter)
{
columnNameAndSize.Zero();
columnNameAndSize.Append(colIter->iName);
columnNameAndSize.Append(KDelimiter);
if(colIter->iType==EDbColText)
columnNameAndSize.AppendNum(colIter->iMaxLength);
else
columnNameAndSize.Append(KNoSize);
resultArray->AppendL(columnNameAndSize);
colIter++;
}
CleanupStack:
:
PopAndDestroy(colSet);
CleanupStack:
:
Pop(resultArray);
//PopthebooksTablefromcleanupstackandcloseit.
CleanupStack:
:
PopAndDestroy();
returnresultArray;
}
2.5打开/关闭数据库
在2.2中讨论了,数据库可以以专有的客户端模式打开,或以共享的C/S模式打开。
RDbNameDatabase支持这两种模式,RDbStoreDatabase仅支持客户端模式。
推荐使用RDbNameDatabase。
客户端访问数据库更有效率,但数据库不能被其他应用程序访问,因为在访问期间,数据库文件已被锁。
Client/Server模式
下面的代码片段演示了以C/S模式打开和关闭数据库,代码实现需要RDbNameDatabase和数据库服务器会话类RDbs。
...
private:
//Memberdata
RDbsiDbSession;
RDbNamedDatabaseiBookDb;
...
voidCBookDb:
:
OpenDbInClientServerModeL(constTFileName&aExistingBookFile)
{
User:
:
LeaveIfError(iDbSession.Connect());
User:
:
LeaveIfError(iBookDb.Open(iDbSession,aExistingBookFile));
}
...//Usetheopendatabase
voidCBookDb:
:
CloseDb()
{
iBookDb.Close();//notetheorderofclosing.
iDbSession.Close();
}
Client-side模式
下面代码示例了使用RDbNameDatabase以Client-side模式打开和关闭数据库。
代码跟前面的C/S模式类似,不用的是使用文件服务器会话RFs,而不是数据库服务器会话RDbs。
...
private:
//Memberdata
RFsiFsSession;
RDbNamedDatabaseiBookDb;
...
voidCBookDb:
:
OpenDbInClientSideModeL(constTFileName&
aExistingBookFile)
{
User:
:
LeaveIfError(iFsSession.Connect());
User:
:
LeaveIfError(iBookDb.Open(iFsSession,aExistingBookFile));
}
...//Usetheopendatabase
voidCBookDb:
:
CloseDb()
{
iBookDb.Close();//notetheorderofclosing.
iFsSession.Close();
}
如果是RDbStoreDatabase,流和会话必须要正确地处理。
...
private:
//Memberdata
RFsiFsSession;
RDbStoreDatabaseiBooksDb;
CFileStore*iFileStore;
...
TIntCBookDb:
:
OpenDb(constTFileName&aExistingBookFile)
{
Close();
if(!
BaflUtils:
:
FileExists(iFsSession,aExistingBookFile))
{
returnKErrNotFound;
}
TRAPD(error,
iFileStore=CPermanentFileStore:
:
OpenL(iFsSession,
aExistingBookFile,EFileRead|EFileWrite);
//Setfilestoretype
iFileStore->SetTypeL(iFileStore->Layout());
iBookDb.OpenL(iFileStore,iF