Delphi下SQLite编程初探

页面导航:首页 > 软件编程 > Delphi > Delphi下SQLite编程初探

Delphi下SQLite编程初探

来源: 作者: 时间:2016-01-21 09:33 【

文/图 sislcb这篇文章介绍我在使用Delphi7+SQLite3过程中遇到的问题,然后以一个完整的实例说明SQLite在Delphi中的使用方法。 起因 我看到《承影随时学英语2.0》这个软件,觉得很不错,于是
文/图 sislcb
这篇文章介绍我在使用Delphi7+SQLite3过程中遇到的问题,然后以一个完整的实例说明SQLite在Delphi中的使用方法。

起因
我看到《承影随时学英语2.0》这个软件,觉得很不错,于是下来看了一下,发现使用了SQLite数据库,利用的是ODBC连接方式,于是我也有了自己写一个类似程序的想法,毕竟这是别人的东西,自己写的话,用起来感觉就不一样了,说干就干。

SQLite介绍
SQLite是一个老牌的轻量级别的本地文件数据库,完全免费且开源,不需要安装,无须任何配置,当然,这样管理功能就不是很强大了,但是它的主要应用也是在本地数据库,应该说是最简单好用的嵌入式本地数据库了吧。象FireBird虽然也提供了嵌入式数据库,但是它自身附带的DLL太多,看起来没那么清爽,而SQLite只要一个DLL就可以实现全部功能。SQLite不需要数据库引擎,只有一个数据文件,占用系统资源非常少,很适合做Demo或小型应用。同时,SQLite也是关系型数据库,支持大部分SQL语句,这是它比BDB(Berkely DB)优秀的地方,当然性能跟它比还是有差距的。它支持事务机制和blob数据类型,支持大部分SQL92标准,最大支持数据库到2T。它还有Python、Tcl、PHP、Java的绑定,这些语言可以直接使用SQLite数据库,因为它们自身包含了支持;还有ODBC接口,非常方便使用。
SQLite的一些基本操作跟SQL很类似,基本上有SQL基础的都能看明白。SQLite的图像查看工具有很多,比如SQLiteSpy、SQLiteBrowser等。我这里使用的是SQLiteSpy。
SQLite默认是utf8编码,使用pragma encoding可以看出数据库的编码。建立数据库后,可以直接输入“pragma encoding = UTF8/UTF16”来改变编码,但数据库有了数据以后,编码是不可以修改的。
SQLite的可以http://www.sqlite.org获得。关于SQLite的更进一步的语法和信息,请参http://www.sqlite.com.cn/

Delphi的SQLite组件介绍
Delphi是一个很优秀的开发工具,虽然它自身没提供对SQLite的支持,但已经有人开发出了第三方控件,非常方便。不用直接使用SQLite提供的API,只要你拖下控件,设置下属性就行了。支持SQLite的控件有两个:ASQLite和ZEOSDBO,其中ASQLite是专门为SQLite编写的,ZEOSDBO是支持很多的,包括Oracle、Firebird等,类似于dbexpress,但应该比它强大。
ASQLite是一个Delphi的开源封装库,发布包中有两个子压缩包,其中ASQLite(ASQLiteD4和ASQLiteD5)是开发时的调试,ASQLitePkg (D4/D5)是发布时的运行组件。ZEOSDBO是基于VCL标准的数据库接口实现,可以像BDE、ADO、DBX那样使用这一组控件,它不但可以访问免费的小型的数据库,而且MSSQL、DB2、、也同样支持。支持的VCL开发工具有Delphi 5-10、BCB 5/6、Kylix 2/3、Lazarus等。访问任何数据库都是统一的控件,只要选择不同的Protocol就可以了,确实是非常方便和强大的。

程序的设计
有了上面的基础知识,我们就可以进行程序的设计了,首先必须明确程序的功能。软件的功能需求有:1)基本功能:背诵单词/句子;2)控制功能:播放/暂停/设置播放时间;3)设置窗体属性:置顶/透明;4)杂项:历史/退出。
有了需求后,就是怎么设计的问题了。首先是数据库的设计,打开SQLiteSpy,点击“New DataBase”,弹出对话框后,输入你想保存的数据库名字,点保存;接着在SQLiteSpy右上的空白处输入如下代码:

CREATE TABLE English900
(
[explain] varchar(256),
word  varchar(256),
xuhao integer  
);
CREATE TABLE EnglishWord
(
xuhao integer,
[explain] varchar(256),
word  varchar(256)
);

explain是SQLite的关键字,所以需要加上括号!之后就可以看到建立好的表了,建立了表之后,我们就需要把数据导进来了。而要把已经存在的数据导入,需要把有数据的表也打开。SQLite只有一个Main数据库,所以需要用“Attach Database”命令把已经存有数据的数据库附加到现在的数据库。这时候的界面如图1所示。这样就打开了两个数据库,接着是导入命令:



insert into english900(fanyi,juzi,xuhao) select * from [englishdb].english900;
insert into englishword(xuhao,[explain],word) select * from [englishdb].englishword;

就可以把englishdb里面两个表的内容导入到现在的Main数据库表中。好了,数据库部分就完成了。
继续软件的设计,我的思路是这样的。先使用ASQLite或者ZEOSDBO把数据Select出来,接着放到内存表里面,准备使用ClientDataSet,然后把ASQLite或者ZEOSDBO关掉,这样就不会一直保存着连接了。而且把数据保存在内存里,不用每次拿一个单词或者句子出来,都要跑到数据库里面去取,速度应该相对来说快一点了。
接着是显示问题,我不想按照数据库的顺序取出来,而是随机取,这样随机的算法怎么设计呢?第一个笨办法是在ClientDataSet里面动态增加一个字段,用来判断该单词/句子是否已经被读取过了,读取过一次后,就对该字段置为True。但这个办法很不好,假如随机到的单词/句子都是读取过的,那不是要判断好久,太没效率了。还好这时候老张(一个同事)给了一个办法:分段随机。第一次从1-10开始随机取一个,然后从10-20,依此类推。我觉得这个方法挺不错,就采用了。这样把数据保存在内存表后,使用定时器固定一段时间就把单词/句子显示出来。确定了方案后,就开始编码了。

程序的编码
由于ASQLite是专门对SQLite进行定制的,所以我估计它在功能等方面应该会好点吧。于是我首先选择了ASQLite做为数据库连接组件。使用的控件有“DBConn:TASQLite3DB;”、“ASQLQuery:TASQLite3Query;”、“cdsCache:TclientDataSet;”、“dspCache:TdataSetProvider;”。

1)设置DBConn
var
Dir:String;
begin
//得到程序目录
Dir := ExtractFilePath(Application.ExeName);
//设置查找目录,否则会出现找不到db和dll错误
DBConn.DefaultDir := Dir;
//加入数据库不存在,则自己创建
DBConn.Database  := DBmyEnglishDB.db;
DBConn.DriverDLL := DLLSQLite3.dll;
DBConn.Connected := True;
end;

以上动态修改DBConn的属性,假如直接给它的Database赋值,那就定死在那个文件夹了。这里要注意,由于有DefaultDir属性,所以设置了之后,在Database等属性中,就不用加上Dir了,默认就是在这个路径寻找的。
2)设置ASQLQuery
Connection属性设置为 DBConn。
3)设置dspCache
DataSet属性设置为ASQLQuery;。
4)设置cdsCache
ProviderName设置为dspCache;。

这样,组件就设置完成了,接下来是按钮事件。背诵单词按钮事件处理如下。

if (Sender as TMenuItem).Checked then
Exit
else
begin
(Sender as TMenuItem).Checked := True;
pm_control_sentence.Checked := False;
with ASQLQuery do
begin
if Active then
Close;
SQL.Clear;
SQL.Text := select * from englishword;
Open;
end;
cdsCache.Data := dspCache.Data;
ASQLQuery.Close;

在把数据保存到ClientDataSet后,就把ASQLQuery关闭。背诵句子的事件和这个类似,就不贴出来了。
以上编译好后,在测试过程中出现问题了。问题出在这一句:“cdsCache.Data := dspCache.Data”。当我来回切换背诵单词和背诵句子按钮时,会出现一个错误,而且错误是定位在ASQLite的GetFieldData里面,莫非控件自身有bug?后来我又测试了一些方法,不使用clientdataset和datasetprovider,直接从ASQLiteQuery里面把数据取出来,还是发现有问题,在尝试几次获取数据之后,就会出现这个错误。看来控件出问题的可能性很大了,不过里面的源码我也不是很看得明白,所以没办法修复,只好转向了ZEOSDBO,希望能找到转机吧。
于是去sourceforge把ZEOSDBO控件下载下来,把ASQLQuery和DBConn删除掉,把ZEOSDBO的Zconnection和Zquery放上去,cdsCahe无须修改,把dspCache的Dataset设置为Zquery就可以了。然后是设置Zconnection和Zquery,具体如下。
1)Zconnection
Dataabase属性设置为:DBmyEnglishDB.db,这个是数据库文件所在的地方。
Protocol属性设置为:sqlite-3,这样就支持SQLite3的数据库了。
2)Zquery
只需设置Connection的属性指向ZConnection控件就可以了。
背诵单词的代码如下。

if (Sender as TMenuItem).Checked then
Exit
else
begin
(Sender as TMenuItem).Checked := True;
pm_control_sentence.Checked := False;

with ZROQ do
begin
if Active then
Close;
SQL.Clear;
SQL.Text := select * from englishword;
Open;
end;
cdsCache.Data := dspCache.Data;
//本来想给它动态增加一个字段,然后根据这个字段判断是否已经显示过了,但感觉这样有个问题,假如随机产生的数一直都是显示过的,这样判断起来的话,就非常不爽,而且感觉这种方法太笨了,穷举……
//cdsCache.FieldDefs.Add(IsShow,ftInteger);
ZROQ.Close; //保存到内存表后,把ZQuery关闭,这样就不会占用一个连接了。
tmShow.Enabled := True; //设置定时器启动,每隔一段时间就可以把数据显示在界面上了。

执行select语句后,却发现读出来的数据是乱码,但不会出现和ASQLite类似的问题了。这至少说明了ASQLite应该是有问题的,看来接下来就是要解决编码问题了。在网上搜索了一些资料,没发现类似的解决方法。于是我开始怀疑是数据库编码问题,因为默认是ut
Tags:

相关文章

    文章评论

    最 近 更 新
    热 点 排 行
    Js与CSS工具
    代码转换工具
    
    <