Delphi 2010安装及使用UniDAC 4.0mysql
UniDAC是一个功能强大的非可视化跨数据库的数据访问组件,可用于Delphi,Delphi for .NET,C++Builder,and Lazarus (Free Pascal)。它提供了对流行数据库服务器的统一访问,像Oracle,Microsoft SQL Server,MySQL,InterBase,Firebird,PostgreSQL,SQLite,DB2,Microsoft Access,Sybase Advantage Database Server,Sybase Adaptive Server Enterprise,和其余数据库(使用ODBC驱动)。
从网上下载到UniDAC 4.0的源码版本,安装过程以下:
1.进入"...\unidac40src\Source\Delphi14"文件夹,找到"Make.bat"文件,打开并修改IDE目录路径,以下:
set IdeDir="%PROGRAMFILES%\Embarcadero\RAD Studio\7.0
call ..\Make.bat Delphi 14 WIN32
由于我这里Delphi 2010不是安装在默认位置,故修改以下:
set IdeDir="D:\Program Files\Embarcadero\RAD Studio\7.0
call ..\Make.bat Delphi 14 WIN32
2.执行"Make.bat"文件,自动执行一系列操做后,到"...\unidac40src\Bin\Delphi14"目录下,可发现库已经生成完毕;
3.运行Delphi 2010,菜单→"Tools"→"Options"→"Environment Options"→"Environment Variables",添加"...\unidac40src\Bin\Delphi14"完整路径到"PATH"环境变量;
4.菜单→"Component"->"Install Packages...","Add"添加"...\unidac40src\Bin\Delphi14"目录下的"dclunidac140.bpl";
5.菜单→"Tools"→"Options"→"Environment Options"→"Delphi Options"→"Library - Win32",在"Library Path"添加"...\unidac40src\Lib\Delphi14"路径;
6.此时,已可使用UniDAC链接数据库了。如果须要连接查看源代码,将"...\unidac40src\Source"路径也添加到"Library Path"。
测试链接MySql数据库:
1.新建一个应用程序,在面板上拖动TUniConnection、TMySQLUniProvider、TUniQuery、TUniDataSource、TDBGrid到窗体上,以下图所示:linux
2.右键TUniConnection,选择"Connection Editor...",填入数据库链接参数,以下图所示:
c++
3.由于MySql通常设置字符集为UTF-8,而Delphi 2010工程字符集是Unicode,在"Options"页面,设置"UseUnicode"为True,这能够通知服务器,客户端和服务器双方之间的全部数据都将经过UTF-8编码,设置这个选项会转换全部的TStringField字段类型到TWideStringField字段类型,使得几乎全部的语言符号均可以正确工做,但另外一方面,也引发工做延迟。web
4.关联其余项,在TUniQuery的SQL里面写"select * from city",设置Active为True,运行程序,能够看到符号均可以正常显示,以下图所示:算法
代码实现的方式以下:sql
procedure TForm1.FormCreate(Sender: TObject); begin UniQuery1.Connection := UniConnection1; UniDataSource1.DataSet := UniQuery1; DBGrid1.DataSource := UniDataSource1; with UniConnection1 do begin ProviderName := 'MySQL'; Username := 'root'; Password := '123'; Server := '192.168.82.201'; Database := 'world'; Port := 3306; SpecificOptions.Values['UseUnicode'] := 'True'; try Connect; UniQuery1.Close; UniQuery1.SQL.Text := 'select * from city'; UniQuery1.Open; except end; end; end;
delphi2010下安装UniDac数据库
1. 进入 Source/Delphi14,编辑Make.bat 批改IdeDir="D:/Program Files/Embarcadero/RAD Studio/7.0 为你的Delphi2010安装路径,重视:双引号只有前半项目组,没有后半项目组。
2. 履行Make.bat。完成后在当前目次生成一个Unidac的目次。
3. 批改文件夹属性,把全部文件夹的隐蔽属性去掉。(针对win7,winxp下可省略这一步)
4. 批改C:/Users/All Users/Documents/RAD Studio/7.0/Bpl的接见权限,只要能进入便可。办法以下:右键点击Documents,在属性的“安然”页中选“高等”。高等页面中有一项“拒绝”,选中它,点击”更改权限”,再点击”编辑”,选中”彻底把握”,一路判定。(针对win7,winxp下可省略这一步)
5. .把Unidac目次下*.bpl复制到C:/Users/All Users/Documents/RAD Studio/7.0/Bpl下。(针对win7,winxp下可省略这一步)
6. 打开Delphi2010,从菜单Component->Install Packages 安装dclunidac140.bpl。
7. 把Source目次添加到delphi的library路径,操纵路径为:tools->options->environment options->Delphi options->library-win32,在library path中输入。(winxp下可省略这一步,由于第六步操纵完后已经在library path中参加路径)
8. 把Source/Delphi14/UniDAC/Lib目次添加到delphi的library路径。
9. OK,现在能够链接各种数据库啦
express
uniDAC用法总结编程
常言道,细微之处见体贴。UniDAC有一些过人的方法或属性。
好比,刷新单条记录(RefreshRecord)、多表更新的属性(UpdatingTable)、宏替换参数(Macros)、
集成删除/新增/修改/刷新/锁定SQL语句、FetchRows,更让人称道的是引入了UpdateSQL组件。
TUniTable、TUniQuery和TUniStoredProc是用来检索和编辑数据的UniDAC控件.
***************************TUniQuery******************************************************
UniDirectional属性
ADO没有单向数据集特性,全部的数据下载到本地,不停的开辟内存或释放大内存,对三层的内存是一个极大考验。TUniQuery有一个 UniDirectional属性,支持单向速度,这点和DBX的想法不谋而合。何况,单向数据集特性速度很是快,在三层中,配合 TDataSetProvider,中间件将其Data包发送到客户端,速度无可比拟。ADO也有流或XML格式包,但不管是XML或流格式,数据包远比 CDS的包大几倍。CDS封包技术很好!
FetchRows能够设定一次获取记录的行数
uniquery 和 unitable 的 SpecificOptions 属性,须要设置 FetchAll=False才能使 FetchRows 的设置生效,而默认状况下, oracle 是设置Oracle.FetchAll=False;
而对去 sql server 和 mysql 等,倒是设置的 XXX.FetchAll=True
UniQuery.SpecificOptions.Values['FetchAll'] := BoolToStr(cbFetchAll.Checked, True);
UniDirectional属性
ADO没有单向数据集特性,全部的数据下载到本地,不停的开辟内存或释放大内存,对三层的内存是一个极大考验。TUniQuery有一个 UniDirectional属性,支持单向速度,这点和DBX的想法不谋而合。何况,单向数据集特性速度很是快,在三层中,配合 TDataSetProvider,中间件将其Data包发送到客户端,速度无可比拟。ADO也有流或XML格式包,但不管是XML或流格式,数据包远比 CDS的包大几倍。CDS封包技术很好!
UniDAC的单条记录刷新
一、设置 SQLRefresh.TEXT的刷新SQL,通常要具体到单条记录。好比:SQLRefresh.Text:='SELECT * FROM TName WHERE ID = :ID'(其中ID是表TName的主键,以确保返回只有一条记录)
二、设置 TRefreshOptions为 [roAfterInsert,roAfterUpdate],即为新增后刷新,修改后刷新。
三、调用 UniQuery1.RefreshRecord
若是不作以上设置,仅执行UniQuery1.RefreshRecord 是一点反映也没有的
UpdatingTable
属性 UpdatingTable 服务显示表将被更新(若是在查询中有许多表)。若是它的值为空,正在使用的表就会显示SQL操做的结果。 为了更好地对查询结果进行操做,建议应老是设置属性UpdatingTable
cachedupdates缓存更新
UniQuery默认状态为行提交,使用前根据须要设置readonly或cachedupdates属性
Filter过滤
UniQuery.Filter默认大小写区分,请注意设置FilterOptions属性([foCaseInsensitive]),TVirtualtable也存在相同状况
在UniQuery的SQL定义参数
咱们常常会在UniQuery的SQL定义一些参数,在传参时,须要特别注意,例如:
QExec.Close;
QExec.SQL.Text:= ‘select * from YHB where sYHBH=_YHBH’;
在传参时有两种写法
1)最稳妥的写法
QExec. ParamByName(‘P_YHBH’).DataType:= ftString;
QExec. ParamByName(‘P_YHBH’).ParamType:= ptInPut;
QExec. ParamByName(‘P_YHBH’).AsString:= ‘张三’;(此处可将AsString换成Value)
2)下面这个写法我作了简单测试,也是能够的,但对复杂的SQL传参是否正确,未知
QExec. ParamByName(‘P_YHBH’).AsString:= ‘张三’;(在不对参数的数据类型和传入传出类型进行指定的状况下,绝对不能使用Value)
UniQuery.SetReadOnly属性
1) 咱们常常会用到多表关联,且须要在前台修改数据。举个例子:a表和b表,在前台两个表字段都须要修改,则须要将SetReadOnly设置成false
2)特别注意:若将一个UniQuery.SetReadOnly设置成true,而这个表有一个自增加ID,那么你在提交数据时会出错,跟踪SQL会发现,ID被前台前行传了一个null值
UniQuery. RefreshRecord
能够刷新当前选择的数据
数据提交
数据提交的顺序,必定要注意:windows
with MyQuery do begin Session.StartTransaction; try ... {Modify data} ApplyUpdates; {try to write the updates to the database} Session.Commit; {on success, commit the changes} except RestoreUpdates; {restore update result for applied records} Session.Rollback; {on failure, undo the changes} raise; {raise the exception to prevent a call to CommitUpdates!} end; CommitUpdates; {on success, clear the cache} end;
对于单数据集的提交:
MyQuery. ApplyUpdates;
MyQuery. CommitUpdates;
Unidac:解决“trying to modify read-only Field”问题!
后台使用SQL语句中,常常会关联自定义函数或视图,而CDS(TClientDataSet)对字段校验比较严格,涉及到的自定义函数或视图输出的字段,都会强制改成ReadOnly为True属性。
当后台使用UniDAC+CDS,关联视图或自定义函数,为了数据一致性,有可能须要在前台界面上修改CDS相关的自定义函数输出的字段,即使是将 该字段设置为 readonly为false,
或将其字段的 FieldDefs属性的attributes的faReadOnly去掉,系统也会抛出一个异常:trying to modify read-only Field。
解决问题很简单,将TUniQuery.Options.SetFieldsReadOnly为false便可。
查一下TUniQuery.Options.SetFieldsReadOnly的帮助,这样写道:
If True, dataset sets the ReadOnly property to True for all fields that do not belong to UpdatingTable or can not be updated. Set this option for datasets
that use automatic generation of the update SQL statements only.
Macros属性
要注意:若是要替换的值是一个字符串,那么记得在字符串两边加''号,由于Macro只是一个简单的替换功能,他不会去判断条件的类型。
其余
UniQuery默认状况下,有些varchar类型的字段有自动加了一个空格,请注意设置Options.TrimVarChar=true
UniQuery在进行Insert时,若字段不能为null且前台操做未填写时,可能会报错,请设置RequiredFields=true
UniQuery在修改数据集时,默认的方式是按关键字生成SQL语句进行数据提交。还有另外两种方式:一是设置updateSQL,一是设置KeyFields(具体请sql跟踪查看)
UniQuery的数据排序属性是IndexFieldNames
********************存储过程*************************************************************************
TUniConnection, TUniSQL, TUniQuery, TUniStoredProc都可以执行存储过程。
TUniConnection:
是一种最简单的执行存储过程的控件,但他有不少限制。TUniConnection不能具备SQL、存储过程名和参数,不支持输出参数也不支持存储执行的预准备。固然,若是只是运行一个既没有返回也没有输出参数设置,那TUniConnection是一个不错的选择。
TUniSQL:TUniSQL是一个被分离出的小控件,执行SQL语句但不返回结果集。它没有数据存储,但要消耗一些内存,但比TUniQuery和TUniStoredProc的执行速度快。
UniSQL.SQL.Text :=str
UniSQL.Execute;
s := 'Rows affected: ' + IntToStr(UniSQL.RowsAffected);
TUniQuery:TUniQuery除具备TUniSQL的执行功能外,还能返回结果集。
TUniStoredProc:TUniStoredProc是专门用来执行存储过程的一个控件,能够返回结果集、输出参数、执行准备以及经过CreateProcCall方法初始化等。
一、 参数类型
UniDAC支持四种参数类型:input, output, input/output, result
***********************************************TUniConnection************************************************************
事务
TUniConnection经过StartTransaction, Commit, Rollback等方法来控制本地事务,判断一个事务是否开启用InTransaction。
一、TUniConnection
创建和控件数据链接的控件,能访问的数据库包括:Oracle, SQL Server, MySQL, InterBase, Firebird, 和PostgreSQL.
虽然UniDAC对不一样的数据库提供了统一的访问接口,可是对个别数据库仍是要进行一些特殊的设置,这些设置是一个字符串列表,你能够按如下代码进行设置:
UniConnection.SpecificOptions.Values['CharLength'] := '1';
一、 Oracle
unidac 怎么对数据的插入和更新
一、使用unidac 如何获得有返回是否插入数据成功
二、使用unidac 如何获得有返回是否更新数据成功
下面是我关于数据查询和无返回结果的插入数据,求教如何处理上面的两个问题
--数据的查询
with form1.UniQuery1 do form1.UniQuery1.Close; form1.UniQuery1.SQL.Clear; form1.UniQuery1.SQL.Add('select TareNo 皮重号,TareWeigth*0.001 重量 from umttare_tmp'); form1.UniQuery1.Open;
--无返回值的插入数据
form1.UniQuery4.Close; form1.UniQuery4.SQL.Clear; form1.UniQuery4.SQL.Text:='insert UMTTare_Tmp (ScaleID,TareNo,TareWeigth,dummy) values(0,:a,:b,null)'; form1.UniQuery4.ParamByName('a').Value := form1.Edit1.Text; form1.UniQuery4.ParamByName('b').Value := form1.Edit2.Text; form1.UniQuery4.ExecSQL; UniTable2.Open; UniTable2.Append; TBlobField(UniTable2.FieldByName('CONTENT')).LoadFromFile('d:\PackageRequires.exe'); UniTable2.Post; UniQuery1.Close; UniQuery1.SQL.Text := 'SELECT * FROM TESTBLOB WHERE ID=9'; UniQuery1.ExecSQL; TBlobField(UniQuery1.FieldByName('CONTENT')).SaveToFile('d:\system\desktop\d.exe');
unidac直连oracle导入图片到表中
var UniConnection: TUniConnection; UniQuery: TUniQuery; begin UniConnection:= TUniConnection.Create(nil); UniQuery:= TUniQuery.Create(nil); UniConnection.ProviderName := 'ORACLE'; UniConnection.SpecificOptions.Clear; UniConnection.SpecificOptions.Values['Direct'] := 'True'; UniConnection.Server := 'host:port:database'; UniConnection.Username := 'username'; UniConnection.Password := 'passwd'; UniConnection.Connect; UniQuery.Connection := UniConnection; UniQuery.SQL.Text := 'insert into temp3 (a4,a6) values (:a4,:a6)'; UniQuery.ParamByName('a4').AsString := 'pic1'; UniQuery.ParamByName('a6').ParamType := ptInput; //这句是必要的 UniQuery.ParamByName('a6').LoadFromFile('1.jpg',ftOraBlob); UniQuery.Execute; end; 若是加这句UniConnection.SpecificOptions.Values['UseUnicode'] := 'True';就执行报错
基于UniDac的数据库链接池
上篇提到了在XE~XE6下安装UniDac。这篇,就基于UniDac,实现一个简单的数据库链接池。
文本的目录:
一、简单描述链接池实现的好处和原理;
二、链接池实现代码;
三、给出使用链接池的Demo(窗体文件代码 和 实现Pas代码);
本文全部的代码在XE环境上测试经过。若是要运行在XE如下版本,Demo请根据实现状况做修改。
一、简单描述链接池实现的好处和原理
如今开始介绍第1点,使用Delphi开发数据库应用软件,那是一把利器。固然,Delphi也能开发其它类型的产品,好比游戏之类,盛大的传奇就是用Delphi开发的;固然今天的话是数据库应用。不少的ERP,我了解的金蝶ERP和用友ERP就是用Delphi开发的,固然他们也有Web版本。MIS系统初期时基于单机版本,如今不少财务软件就有单机版本,后来发展成C/S架构,就是客户端-服务端架构,客户端提供UI界面,服务端实现业务逻辑;在后来就发展到多层结构,一直到N层,实现分布式结构。其实无论是单机结构,仍是C/S结构,仍是发展到目前的三层及多层结构,自己并对业务逻辑的编写,并无多大差异。资料的CURD(C=Create,U=Update,R=Read ,D=Delete)操做都是同样。这就涉及到一个问题。在链接数据库,包括ODBC,ADO,ADO.net 仍是 DBExpress,仍是第三方的链接驱动,都是程序和数据库的链接通道,本文的UniDac也是一个通道。咱们知道每一次数据库链接,都是须要消耗资源,包括TCP/IP链接,SQL缓存等开销。如今的问题,若是有一个 Pool,能把每次申请的SQLConnetion用完后,再放回池里,不释放,以备下次使用,那样不是节省了开销,又增长了效率,让链接访问数据库为更快速,特别是多线程下,对数据库的访问。那么实现原理是什么呢?能够设计简单或设计复杂,这要视实际状况而定。通常的思路,池对外提供一个接口,供程序调用。若是没有SQL链接,池本身生产一个,返回SQL链接对象;程序调用完,池就回收,不实际释放,等待下次调用。这里有个问题,就是控制池的最大链接数问题,不过对于通常的应用,这个问题能够先不用考虑。下面是访问时序图:
二、链接池实现代码:
{ Author: Purpose: 数据库链接池单元 History: Modify desc: 本链接池针对MySQL数据库,根据实际状况,能够配置MSSQL,Oracle,DB2,SQLite等,固然具体中,要稍做修改 } unit SqlConPool; interface uses SysUtils, Windows, Classes, IniFiles, Uni, MySQlUniProvider, MemDS; // const // AESKey = '3ABE2C927E89407D95AF-B4DCB0AD76FEF8F45194167A465F94C29E2ABB6E67C2'; type TSQLConntionRecord = record HostName: string; Port: Integer; UserName: string; DBName: string; MyDataBase: string; Password: string; end; TSQLConnectionPool = class private FDbType: string; FConList: TThreadList; function TestConnection(con: TUniConnection): boolean; function GetConnection: TUniConnection; function GetConnectionRecord: TSQLConntionRecord; public function Pop: TUniConnection; procedure Push(con: TUniConnection); constructor CreatePool; destructor Destroy; override; function GetDbType: string; function PoolCount: Integer; end; TQryPool = class private function GetQry: TUniQuery; procedure con(qry: TUniQuery); procedure discon(qry: TUniQuery); public function Pop: TUniQuery; procedure Push(qry: TUniQuery); end; var SQLConnectionPools: TSQLConnectionPool; QryPools: TQryPool; implementation { TSQLConnectionPool } constructor TSQLConnectionPool.CreatePool; begin FConList := TThreadList.Create; FDbType := 'MYSQL'; end; destructor TSQLConnectionPool.Destroy; var i: Integer; begin with FConList.LockList do try for i := Count - 1 downto 0 do begin TUniConnection(Items[i]).Close; TUniConnection(Items[i]).Free; end; finally FConList.UnlockList; end; FConList.Free; end; //获取SQL链接对象 function TSQLConnectionPool.GetConnection: TUniConnection; var con: TUniConnection; RecCon: TSQLConntionRecord; begin Result := nil; try con := TUniConnection.Create(nil); RecCon := GetConnectionRecord; try with con do begin LoginPrompt := false; ProviderName := RecCon.MyDataBase; UserName := RecCon.UserName; Password := RecCon.Password; Server := RecCon.HostName; Database := RecCon.DBName; Port := RecCon.Port; // 解决中文乱码,UniCode编码 SpecificOptions.Values['UseUnicode'] := 'True'; Connect; end; Result := con; except on E: exception do begin Result := nil; con.Free; // 打印日志。。。。 end; end; except end; end; //获取配置SQL链接参数 function TSQLConnectionPool.GetConnectionRecord: TSQLConntionRecord; var dbIni: TIniFile; begin dbIni := TIniFile.Create(ExpandFileName(ExtractFilePath(ParamStr(0)) + '\DataBase.ini')); try with Result do begin HostName := dbIni.ReadString('Database', 'Host', ''); Port := dbIni.ReadInteger('Database', 'Port', 3306); UserName := dbIni.ReadString('Database', 'UID', ''); DBName := dbIni.ReadString('Database', 'Database', ''); MyDataBase := UpperCase(dbIni.ReadString('Database', 'DataBaseType', 'MySql')); Password := dbIni.ReadString('Database', 'Password', ''); // 若是要加密处理,就经过DES或AES加密 // Password := string(AesDecryptString(dbIni.ReadString('Database', // 'Password', ''), AESKey)); end; finally dbIni.Free; end; end; //获取数据库类型,UniDac支持多种数据库类型,能够经过配置文件配置 function TSQLConnectionPool.GetDbType: string; begin Result := FDbType; end; //获取链接池SQL对象个数 function TSQLConnectionPool.PoolCount: Integer; begin with FConList.LockList do try Result := Count; finally FConList.UnlockList; end; end; //弹出SQL链接对象 function TSQLConnectionPool.Pop: TUniConnection; begin with FConList.LockList do try if Count > 0 then begin Result := TUniConnection(Items[0]); Delete(0); if not TestConnection(Result) then begin Result.Free; Result := Pop; end; end else begin Result := GetConnection; end finally FConList.UnlockList; end; end; //回收SQL链接对象 procedure TSQLConnectionPool.Push(con: TUniConnection); begin if con <> nil then with FConList.LockList do try Insert(0, con); finally FConList.UnlockList; end; end; //测试链接池中的SQL对象是否存活 function TSQLConnectionPool.TestConnection(con: TUniConnection): boolean; begin Result := false; try con.ExecSQL('delete from dbcon where 1<>1', []); Result := true; except on E: exception do begin // 实际应用,必定要打印日志 end; end; end; { TQryPool } //qry 关联SQL Connection procedure TQryPool.con(qry: TUniQuery); var sqlcon: TUniConnection; begin sqlcon := SQLConnectionPools.Pop; qry.Connection := sqlcon; end; //回收SQL Connetion 对象 procedure TQryPool.discon(qry: TUniQuery); begin SQLConnectionPools.Push(qry.Connection); end; //获取对象 function TQryPool.GetQry: TUniQuery; var qry: TUniQuery; begin qry := TUniQuery.Create(nil); con(qry); Result := qry; end; //弹出Qry对象 function TQryPool.Pop: TUniQuery; begin Result := GetQry; end; //获取Qry对象 procedure TQryPool.Push(qry: TUniQuery); begin if qry <> nil then begin qry.Close; discon(qry); qry.Free; end; end; initialization SQLConnectionPools := TSQLConnectionPool.CreatePool(); QryPools := TQryPool.Create; finalization if QryPools <> nil then begin QryPools.Free; QryPools := nil; end; if SQLConnectionPools <> nil then begin SQLConnectionPools.Free; SQLConnectionPools := nil; end; end.
三、给出使用链接池的Demo;
窗体代码:
object Form1: TForm1 Left = 0 Top = 0 Caption = 'Form1' ClientHeight = 310 ClientWidth = 682 Color = clBtnFace Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Font.Height = -11 Font.Name = 'Tahoma' Font.Style = [] OldCreateOrder = False PixelsPerInch = 96 TextHeight = 13 object Button1: TButton Left = 24 Top = 8 Width = 138 Height = 25 Caption = #20027#32447#27979#35797 TabOrder = 0 OnClick = Button1Click end object Button2: TButton Left = 24 Top = 55 Width = 138 Height = 25 Caption = #22810#32447#31243#27979#35797 TabOrder = 1 OnClick = Button2Click end object Memo1: TMemo Left = 184 Top = 8 Width = 490 Height = 294 Lines.Strings = ( 'Memo1') TabOrder = 2 end object Button3: TButton Left = 24 Top = 96 Width = 138 Height = 25 Caption = #33719#21462#27744'SQL'#36830#25509#23545#35937#20010#25968 TabOrder = 3 OnClick = Button3Click end end
实现代码:
unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; const WM_PUSHDATA=WM_USER+100; type TForm1 = class(TForm) Button1: TButton; Button2: TButton; Memo1: TMemo; Button3: TButton; procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); procedure Button3Click(Sender: TObject); private procedure GetDtaTest; { Private declarations } procedure WMHandlePUSHDATA(var msg:TMessage);message WM_PUSHDATA; public { Public declarations } end; var Form1: TForm1; implementation uses sqlConPool,uni; {$R *.dfm} //开启多个线程测试 procedure TForm1.Button2Click(Sender: TObject); var i: integer; begin for i := 0 to 50 do begin TThread.CreateAnonymousThread(GetDtaTest).Start; end; end; //显示当前链接池中SQLConnetion对象 procedure TForm1.Button3Click(Sender: TObject); begin ShowMessage(Format('PoolCount=%d',[SQLConnectionPools.PoolCount])); end; //经过获取SQL对象,获取数据 procedure TForm1.GetDtaTest(); var qry: TUniQuery; uid: integer; susername, spw: string; str:String; begin // 获取对象 qry := QryPools.Pop; try with qry do begin SQL.Text := 'select * from user'; Open; while not eof do begin uid := FieldByName('id').AsInteger; susername := FieldByName('username').AsString; spw := FieldByName('password').AsString; str:= Format('id=%d ,username=%s,password=%s',[uid,susername,spw]); //由于若是在工做线程中,避免在主线程下操做UI; SendTextMessage(self.Handle,WM_PUSHDATA,0,str); Next; end; end; finally // 回收对象 QryPools.Push(qry); end; end; //打印显示获取数据 procedure TForm1.WMHandlePUSHDATA(var msg: TMessage); var str:string; begin str:=String( msg.LParam ); Memo1.Lines.Add(str) ; end; //主线程下测试 procedure TForm1.Button1Click(Sender: TObject); begin GetDtaTest(); end; end.
Delphi中SQLite如何读写二进制字段(Blob类型)
在Delphi中,有大量的组件能够操做SQLite数据库,如UniDAC就是其中一个比较优秀的,固然还有ASQLite3Components,也有SQLite3版的ODBC驱动,可直接用ADO操做。本文简要说明SynopseSQLite3读写二进制字段,先说下SynopseSQLite3的优势,静态编译集成SQLite3引擎,不须要额外的DLL支持,支持SQLite3加密,支持JSON表,支持网络版的SQLite3.支持线程安全保护. 首先建一个表,字段类型为BLOBSL.Add('CREATE TABLE IF NOT EXISTS TEST ('); SL.Add('FileName TEXT PRIMARY KEY,'); SL.Add('Data BLOB);'); SL.Add(''); 复制代码写入二进制数据:var FFileStream:TFileStream; FData:array of Char; FSQLR:TSQLRequest; ASQL:AnsiString; begin FFileStream:=TFileStream.Create('test.xml',fmOpenReadWrite); ASQL:='INSERT INTO TEST(FileName,Data) VALUES('+QuotedStr('test.xml')+',?)'; try SQLite数据库对象.Execute('DELETE FROM TEST'); // SetLength(FData,FFileStream.Size); FFileStream.Position:=0; FFileStream.Read(PChar(FData)^,Length(FData)); FSQLR.Prepare(SQLite数据库对象.DB,ASQL); FSQLR.Bind(1,PChar(FData),Length(FData)); FSQLR.Execute; finally FreeAndNil(FFileStream); end; 复制代码其中问号是参数,SQLite数据库对象类型为TSQLDataBase 读取数据并写入到文件:var FBlobField:TSQLBlobStream; FFileStream:TMemoryStream; FData:array of Char; begin try FFileStream:=TMemoryStream.Create; FBlobField:=SQLite数据库对象.Blob('','TEST','Data',1,True); try FBlobField.Position:=0; SetLength(FData,FBlobField.Size); FBlobField.ReadBuffer(PChar(FData)^,FBlobField.Size); FFileStream.Write(PChar(FData)^,FBlobField.Size); FFileStream.SaveToFile("test.xml"); finally FreeAndNil(FBlobField); FreeAndNil(FFileStream); end; except Result:=''; end;
UniDAC使用日记
UniDAC使用日记
1. UniQuery默认状态为行提交,使用前根据须要设置readonly或cachedupdates属性
2. UniQuery.Filter默认大小写区分,请注意设置FilterOptions属性([foCaseInsensitive]),TVirtualtable也存在相同状况
3. UniQuery默认状况下,有些varchar类型的字段有自动加了一个空格,请注意设置Options.TrimVarChar=true
4. UniQuery在进行Insert时,若字段不能为null且前台操做未填写时,可能会报错,请设置RequiredFields=true
5. UniQuery在修改数据集时,默认的方式是按关键字生成SQL语句进行数据提交。还有另外两种方式:一是设置updateSQL,一是设置KeyFields(具体请sql跟踪查看)
6. UniQuery的数据排序属性是IndexFieldNames
7. 数据提交的顺序,必定要注意:
with MyQuery do begin Session.StartTransaction; try ... {Modify data} ApplyUpdates; {try to write the updates to the database} Session.Commit; {on success, commit the changes} except RestoreUpdates; {restore update result for applied records} Session.Rollback; {on failure, undo the changes} raise; {raise the exception to prevent a call to CommitUpdates!} end; CommitUpdates; {on success, clear the cache} end;
对于单数据集的提交:
MyQuery. ApplyUpdates;
MyQuery. CommitUpdates;
8. DataM中提供了一个功能Clone(Source, Dest):1、Dest是TVirtualTable,则完整的将源数据集复制;2、Dest是UniQuery,则是将Source的SQL复制到Dest,并Open
9. UniQuery.SetReadOnly属性说明
1) 咱们常常会用到多表关联,且须要在前台修改数据。举个例子:a表和b表,在前台两个表字段都须要修改,则须要将SetReadOnly设置成false
2) 特别注意:若将一个UniQuery.SetReadOnly设置成true,而这个表有一个自增加ID,那么你在提交数据时会出错,跟踪SQL会发现,ID被前台前行传了一个null值
10.UniQuery. RefreshRecord,能够刷新当前选择的数据
11.咱们常常会在UniQuery的SQL定义一些参数,在传参时,须要特别注意,例如:
QExec.Close;
QExec.SQL.Text:= ‘select * from YHB where sYHBH=:P_YHBH’;
在传参时有两种写法
1)最稳妥的写法
QExec. ParamByName(‘P_YHBH’).DataType:= ftString;
QExec. ParamByName(‘P_YHBH’).ParamType:= ptInPut;
QExec. ParamByName(‘P_YHBH’).AsString:= ‘张三’;(此处可将AsString换成Value)
2)下面这个写法我作了简单测试,也是能够的,但对复杂的SQL传参是否正确,未知
QExec. ParamByName(‘P_YHBH’).AsString:= ‘张三’;(在不对参数的数据类型和传入传出类型进行指定的状况下,绝对不能使用Value)
UniDAC的过程当中必定要注意,在DataM中提供了一个函数PrepareParam,请注意看一下。à在ADO
12.Sybase的一个特性
update a set a.fSJ=b.fSJ
from table1 a join table2 b on a.sYPBSM=b.sYPBSM
上述SQL语句在Sybase下执行不能经过,请改写成以下SQL(在MS和ASE中都能执行经过)
update table1 set fSJ=b.fSJ
from table1 a join table2 b on a.sYPBSM=b.sYPBSM
UniDAC官方网址:http://www.devart.com/
1、链接数据库Connecting to Database
通用链接属性
Provider
第一个就应该设置的属性,指定要链接的数据库类型,根据指定的数据库链接类型不一样其它的设置也会发生相应的变化;
Username and Password
登陆数据的有效用户名和密码;
Server
一般将此设成要链接数据库所在的计算机名或IP地址,若是将此属性设置为空,对于MySQL, InterBase链接数据库方式, UniDAC 将试图链接本地(Localhost)。
Oracle:
客户端模式下,指定的Server名称必定要出如今tnsnames.ora中,且有效,设置效果以下:
with UniConnection1 do begin ProviderName := 'Oracle'; Server := 'ORCL'; Username := 'username'; Password := 'password'; end;
直连模式(Direct mode)下:在此模式下,运行软件的计算机能够不安装Oracle客户端而链接Oracle数据库,但要作如下设置:
设置直连模式
设置Server
指定Server格式:Host:Port:SID.
注:客户端模式和直连模式的设置不能混淆,不然没法执行。两种格式严格区分。
效果以下:
with UniConnection1 do begin ProviderName := 'Oracle'; Server := '192.168.1.113:1521:ORCL'; Username := ' Username '; Password := ' Password 3'; end;
SQL Server:
指定要链接的数据库所在的网络IP,且有效,若是采用的不是默认端口(1433),Server应该这样设置:HostName,PortNumber.
Database
这个属性只对SQL Server, MySQL, PostgreSQL, InterBase, and SQLite 链接方式有效,
Port
指定TCP/IP协议访问的有效端口
MySQL – 默认端口 3306
PostgreSQL -默认端口5432
2、UniDAC(版本:2.7)链接数据库必要文件或局限需求
一、Oracle链接
Oracle在采用直连模式将受到如下限制:
特别要注意的是(包括:应用TUniLoader):
1)、应用直连模式,本地执行程序的客户机必需要安装TCP/IP协议
2)、注意防火墙
3)、数据库的triggers、check constraints、clustered tables、loading of remote objects、user-defined types将得不到支持
4)、available, like OBJECT, ARRAY, REF, XML, BINARY_DOUBLE, BINARY_FLOAT这些类型将变为不可用
5)、TUniLoader的应用版本应高于Oracle client 8.17
如下是英文原文:
triggers are not supported check constraints are not supported referential integrity constraints are not supported clustered tables are not supported loading of remote objects is not supported user-defined types are not supported LOBs must be specified after all scalar columns LONGs must be specified last You cannot use TUniLoader in a threaded OCI environment with Oracle client 8.17 or lower. Connect using the TCP/IP network protocol only. Some types are not available, like OBJECT, ARRAY, REF, XML, BINARY_DOUBLE, BINARY_FLOAT. Certain problems may occur when using firewalls. NLS conversion on the client side is not supported. Transparent Application Failover is not supported. Statement caching is not available. OS authentication and changing expired passwords features are not available. The DES authentication is used. Oracle Advanced Security is not supported. We do not guarantee stability of multithreaded applications. It is highly recommended to use the separate TUniConnection component for each thread when using UniDAC from different threads.
SQL Server链接
提供链接支持
服务端: SQL Server 2005 (including Compact and Express editions), SQL Server 2000, SQL Server 7, and MSDE.
客户端: SQL OLE DB and SQL Native Client.
环境需求
MDAC(Microsoft Data Access Components)版本不低于2.5
My SQL链接
My SQL提供的链接也包括直连和客户端链接方式,默认采用的是直连方式,若是要更改链接方式,在应用程序分发时要带上libmysqld.dll
2、Delphi与各数据库数据类型比较
Delphi数据类型与各数据库数据类型对好比下表,若有具体说明见表中脚注:
Delphi Type Oracle Types SQL Server Types MySQL Types [1] InterBase Types PostgreSQL Types SQLite Types ftSmallint NUMBER(p, 0)[2] (p < 5) SMALLINT TINYINT(M) (M > 1)SMALLINT SMALLINT SMALLINT TINYINTSMALLINT ftWord - TINYINT TINYINT(M) UNSIGNED (M > 1)SMALLINT UNSIGNEDYEAR - - - ftInteger NUMBER(p, 0)[2](4 < p < 10) INT MEDIUMINTMEDIUMINT UNSIGNEDINT INTEGER INTEGER INTEGERINT ftLargeint NUMBER(p, 0)[2] (9 < p < 19) BIGINT BIT INT UNSIGNEDBIGINTBIGINT UNSIGNED BIGINT BIGINT BIGINT ftFloat NUMBER(p, s)[2] BINARY FLOAT(FLOAT)BINARY DOUBLE DECIMAL(p, s)[3] FLOATREAL DECIMAL(p, s)[3] FLOATDOUBLE NUMBER(p, s)[3] FLOATDOUBLE PRECISION DECIMAL[3] REALDOUBLE PRECISION DECIMAL(p, s)[3]FLOATDOUBLE PRECISION ftBCD NUMBER(p, s)[2] (p < 15) and (s < 5) DECIMAL(p, s)[3] (p < 15) and (s < 5) DECIMAL(p, s)[3] (p < 15) and (s < 5) DECIMAL(p, s)[3] (p < 15) and (s < 5) DECIMAL[3] DECIMAL[3] ftFMTBcd NUMBER(p, s)[2] (14 < p < 39) and> (4 < s < 39) DECIMAL(p, s) (14 < p < 39) and (4 < s < 39) DECIMAL(p, s)[3] (14 < p < 39) and(4 < s < 39) DECIMAL(p, s)[3] (14 < p < 19) and(4 < s < 19) DECIMAL[3] DECIMAL[3] ftCurrency - MONEYSMALLMONEY - - MONEY MONEY ftBoolean - BIT TINYINT[4] BOOL[4] BOOLEAN[4] BOOLEAN BOOLEAN BOOLEAN ftString VARCHAR2NVARCHAR2VARCHARCHARNCHARRAW[5] INTERVAL DAY TO SECONDINTERVAL DAY TO MONTHROWIDUROWID CHARVARCHAR CHARVARCHARENUMSETBINARY[6] VARBINARY[6] CHARVARCHAR CHARVARCHAR CHARVARCHAR ftWideString See note [7] NCHARNVARCHAR See note [7] See note [7] See note [7] See note [7] ftMemo LONGAlso see note [8] TEXTNTEXT[9] TINYTEXTTEXTMEDIUMTEXTLONGTEXT BLOB TEXT TEXT TEXTCLOB ftWideMemo See note[10] NTEXT[11] See note[10] See note[10] See note[10] See note[10] ftOraClob CLOBNCLOB - - - - - ftBlob LONG RAW IMAGE TINYBLOBBLOBMEDIUMBLOBLONGBLOBSpatial Data Types BLOB BINARY BYTEA BLOB ftOraBlob BLOB - - - LARGE OBJECT - ftBytes - BINARYTIMESTAMP BINARY - - - ftVarBytes RAW VARBINARY VARBINARY CHARVARCHAR(CHARSET = OCTETS) - BINARYVARBINARY ftDate - - DATE DATE DATE DATE ftDateTime DATE DATE DATETIME TIMESTAMP TIMESTAMP TIMESTAMPDATETIME ftTime - - TIME TIME TIME TIME ftTimeStamp TIMESTAMPTIMESTAMP WITH TIMEZONE - - - - - ftCursor REF CURSOR - - - REFCURSOR - ftGuid - UNIQUEIDENTIFIER - - - - ftVariant - SQL_VARIANT - - - - NOT SUPPORTED BFILEOBJECTXML CURSORXMLTABLE - - - - [1] – 若是FieldsAsString 选项被设置 True,则除BLOB和TEXT数据类型外,所有作为ftString来处理 [2] – Oracle NUMBER数据类型与Delphi数据类型对应方式: if scale equals zero, provider checks values of the specific options to choose the correct Delphi type in the following order: 1.1 field precision is less or equal Precision Smallint (default is 4) - uses ftSmallint; 1.2 field precision is less or equal Precision Integer (default is 9) - uses ftInteger; 1.3 field precision is less or equal Precision LargeInt (default is 18) - uses ftLargeint; if scale is greater than zero, the appropriate Delphi type is chosen using the following sequence of rules:. 2.1 field precision is less or equal PrecisionFloat (default is 0) - uses ftFloat; 2.2 EnableBCD is True and field precision, scale is less or equal PrecisionBCD (default is 14,4) - uses ftBCD; 2.3 EnableFMTBCD is True and field precision, scale is less or equal PrecisionFMTBCD (default is 38,38) - uses ftFMTBCD; 2.4 uses ftFloat. [3] - The appropriate Delphi type is chosen using the following sequence of rules: EnableBCD is True and field precision, scale is less or equal 14,4 - uses ftBCD; EnableFMTBCD is True - uses ftFMTBCD; uses ftFloat. [4] - If the EnableBoolean option is True [5] - If the RawAsString option is True [6] - If the BinaryAsString is True [7] - If the UseUnicode option is True, all server types mapped to ftString will be mapped to ftWideString. [8] - If the LongStrings option is False, and the field length is greater than 255, all server types mapped to ftString will be mapped to ftMemo. [9] - For all Delphi versions prior to BDS 2006. [10] - If the UseUnicode option is True, in BDS 2006 and later versions all server types mapped to ftMemo will be mapped to ftWideMemo. [11] - For BDS 2006 and higher IDE versions.
3、UniDAC更新数据
一、数据自动更新
TUniTable、TUniQuery和TUniStoredProc是用来检索和编辑数据的UniDAC控件,
4、主从关系表
5、存储过程
一、TUniConnection, TUniSQL, TUniQuery, TUniStoredProc都可以执行存储过程。
TUniConnection:
是一种最简单的执行存储过程的控件,但他有不少限制。TUniConnection不能具备SQL、存储过程名和参数,不支持输出参数也不支持存储执行的预准备。固然,若是只是运行一个既没有返回也没有输出参数设置,那TUniConnection是一个不错的选择。
TUniSQL:
TUniSQL是一个被分离出的小控件,执行SQL语句但不返回结果集。它没有数据存储,但要消耗一些内存,但比TUniQuery和TUniStoredProc的执行速度快。
TUniQuery:
TUniQuery除具备TUniSQL的执行功能外,还能返回结果集。
TUniStoredProc:
TUniStoredProc是专门用来执行存储过程的一个控件,能够返回结果集、输出参数、执行准备以及经过CreateProcCall方法初始化等。
参数类型
UniDAC支持四种参数类型:input, output, input/output, result
6、事务处理
TUniConnection经过StartTransaction, Commit, Rollback等方法来控制本地事务,判断一个事务是否开启用InTransaction。
7、控件详解
一、TUniConnection
创建和控件数据链接的控件,能访问的数据库包括:Oracle, SQL Server, MySQL, InterBase, Firebird, 和PostgreSQL.
虽然UniDAC对不一样的数据库提供了统一的访问接口,可是对个别数据库仍是要进行一些特殊的设置,这些设置是一个字符串列表,你能够按如下代码进行设置:
UniConnection.SpecificOptions.Values['CharLength'] := '1';
Oracle
多线程下使用使用 UniDAC+MSSQL
ADO线程不安全,UniDAC 在使用MSSQL也是如此。其实这是微软COM问题,不怪Devart公司。
通常解决方法是在线程开始启用 CoInitialize(nil),线程结束调用 CoUninitialize 。若是你使用多种数据库链接,好比三层中常常切换到MSSQL和Oracle,咱们只需在判断 TUniConnection 的链接前事件 OnBeforeConnect 写下以下代码:
procedure TServDBFunc.ServConnBeforeConnect(Sender: TObject); begin if (ServConn <> nil) and SameText(ServConn.ProviderName,'SQL Server');then CoInitialize(nil); end; 在TUniConnection 的关闭链接后事件 OnAfterDisconnect 写下以下代码: procedure TServDBFunc.ServConnAfterDisconnect(Sender: TObject); begin if (ServConn <> nil) and SameText(ServConn.ProviderName,'SQL Server');then CoUninitialize; end;
须要注意的是,必须先判断链接控件 (ServConn <> nil) 是否为空,不然,你会陷入指针释放的问题。
unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, Grids, DBGrids, DB, DBAccess, Uni, MemDS, UniProvider, InterBaseUniProvider; type TForm1 = class(TForm) UniConnTest: TUniConnection;//用于数据库的链接 InterBaseUniProTest: TInterBaseUniProvider;//ib/FB的数据提供 UniQryTest: TUniQuery; UniDataSrTest: TUniDataSource; DBGrid1: TDBGrid; Button1: TButton; Button2: TButton; procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.Button1Click(Sender: TObject); begin with UniConnTest do begin ProviderName := 'interbase';//这里肯定为interbase 可是能够支持firebird Password := 'masterkey';//数据库密码 Username := 'sysdba';//数据库密码 Server := ''; Database := 'TD_HOUSE.FDB';//数据库文件的位置,这里在当前目录 SpecificOptions.Clear; SpecificOptions.Add('InterBase.ClientLClientLClientLClientLibraryibraryibraryibrary=fbembed.dll'); //设置设置设置设置embeddll驱动位置 SpecificOptions.Add('InterBase.CharLength=0') ;//设置设置设置设置为0让, unidacunidacunidacunidac自动读取fb设置设置设置设置 SpecificOptions.Add('SQLDialet=3'); //设置设置设置设置为3 SpecificOptions.Add('USEUnicode=true');//迟滞unicode 有人说有问题 我没有发现 try Connect; ShowMessage('OK'); except ShowMessage('eer'); end; end; end; procedure TForm1.Button2Click(Sender: TObject); begin UniQryTest.Close; UniQryTest.SQL.Text := 'select * from TB_SYS_LOG'; // UniQryTest.FetchingAll; UniQryTest.DisableControls; UniQryTest.Open; UniQryTest.EnableControls; end; end.
有网友问我经常使用的控件及功能。我先大概整理一下,之后会在文章里面碰到时再仔细介绍。
Devexpress VCL 这个基本上覆盖了系统界面及数据库展现的方方面面,是作桌面系统必备的一套控件,目前的版本是2011.2.3, 支持win32 及win64。
AutoUpgrader 这个是自动更新的一个小控件,适合桌面程序自动更新,可是自从2007 年后,就没有更新了,我对其进行了修改,使其能够安装在delphi XE2 上,
同时支持win64。
Devart 公司出品的UniDAC,ODAC,SDAC,IBDAC, 这几个是目前delphi 数据库存取最好的控件,UniDAC 几乎支持全部的数据库存取,然后面几个则是针对每种
提供专用的访问和控制功能,尤为是ODAC ,能够直接使用TCP/IP 链接oracle,免去安装Oracle客户端的麻烦,很是适合各类场合应用(在xe2 里面,已经能够直接支持用
Iphone 访问oracle了)。
Advanced Data Export 和 Advanced Data Import 这是EMS 公司出品的数据导入、导出控件,几乎能够导入、导出经常使用的各类数据格式,是数据库转换和备份的必备控件。
NativeXml 是生成和解析XML 文件及格式一个非可视控件(使用时,直接引用单元),是一个轻量级的xml 解析器,支持windows 和linux, 之前是收费的,
如今是开源了(唉,惋惜我当时的银子了)。
Paxcompiler 是目前最快的,最稳定的Pascal 脚本解析器,我前面介绍的delphi web 脚本就是使用它作解释器的,目前还不支持win64,据做者说今年元月底就会支持win64.
kbmMW 是目前惟一与Remobjects 并驾齐驱的delphi多层解决方案, 比Remobjects 紧凑、便宜,可是功能毫不输给Remobjects。我后面后介绍使用kbmMW 实现各类多层应用。
TeeChart Pro 在delphi 的图形显示方面目前惟一的选择,虽然从delphi 3 就随delphi 捆绑发布,可是捆绑的是标准版,不少功能都不全,要展现各类绚丽的统计、分析功能,
仍是要用专业版(呵呵,领导们都是喜欢这个的)。最新的TeeChart Pro 已经支持firemonkey了(兼容性还有点问题),你能够把pc 上的绚丽图形放到Iphone 上了。
从 Delphi 1 开始,delphi 每一个版本都会有报表工具,可是每次自带的报表工具都至关不给力,几乎没有人使用,所以出现了几个很是不错的第三方报表工具,例如Reportbuilder,
Fastreport 等,因为今年出的delphi xe2 开始捆绑Fastreport 标准版,同时Reportbuilder 的价格高的离谱,并且fastreport 确实很是不错,建议报表工具仍是用Fastreport.
Delphi 目前应该仍是windows 平台很是强的开发工具,所以常常会用来写windows 服务,虽然Delphi 自己支持winservice 的开发,可是功能也就是能开发而已,要开发专业的
winservice, 仍是要用Svcom , 这个能够像普通程序同样调试服务程序,同时支持 界面和服务在同一个程序里面,调试、配置、安装都很是方便。
这几年随着web 技术的发展,各类JS 框架愈来愈多,与delphi 后台结合,基本上都须要使用JSON 格式,delphi XE 开始支持JSON ,可是我的认为语法复杂,理解困难,
幸亏有开源的Super Object Toolkit,很是直观和简单,在服务器端运行也很是稳定,我上面的文章也有介绍。
以上就基本上是我经常使用的控件,固然还有些控件因为比较偏,就再也不作介绍了。我我的的原则是只要有现成的控件,我不会再去作相似的,毕竟我的精力和能力有限,而人家专业作控件的,
不管从质量和功能上都有保证,同时只要是正版用户,做者都会很及时的修改bug 的,本身把精力放到实现第三方没法实现的地方就能够了
UniDAC使用SQLite数据库可能碰到的问题
若是说要使用第三方控件来连接操做数据库,我想UniDAC绝对是个很好的选择。对于SQLite来讲,像这样能较好支持中文的第三方控件更是少有了。不过使用UniDAC来讲可能会碰到一些有趣的问题,特别是对于新手来讲。如今说说我安装控件后使用SQLite碰到的问题:
1、SQLite3.dll 不能被加载的问题
开始觉得只要在程序主目录下就能够直接在连接时被调用,但其实不是这样的,默认状况下通常是从C:/windows/system32目录下调用的,至少对于编程工具来讲这是默认的调用路径,因此将dll拷到目录下便可解决,这个其实也不算是什么问题。
2、UniDAC这个控件颇有意思,在连接数据库时是不提供打开文件对话框的,若是你直接填写数据库名的话,这个数据库应该会是直接被创建在桌面上了。
3、数据库不能被打开,Database could not be Opened!
听说从3.5版本之后,SQLite是不支持中文路径的,不过我用3.5以上版本也能连接成功,固然,这是在解决问题以后,解决以前的问题是若是把路径设置为英语,那绝对是连接没问题,换中文的话打死也连接不上,因此我想这方面多少应该是有些关系的。
4、SQLite function is not linked!
SQLite的函数未连接,说白了就是函数调用失败,我不知道其它人碰到会是什么样的缘由,但我这里碰到的应该是sqlite3.dll损坏形成的函数调用失败,不能说是确定,但在替换过两次后,连接恢复正常。想了想,用sqlite3.dll的确定不仅一种软件,若是你安装这类软件时,软件没有检查sqlite3.dll的存在和版本,而且直接替换掉了你原来使用的dll,那就颇有可能形成版本不兼容问题,从而致使数据库连接失败,至少我看到了,当我恢复我原来的dll时,另外一个原来使用正常的软件挂掉了……
5、不是问题的问题,用UniDAC设置连接时我常常会看到unsuppored metadata kind ,看上去不是什么特别的异常,应该只是设置连接的步骤不对,先把conneted设置为False再操做就OK了。
让unidac支持加密的sqlite
让unidac支持加密的sqlite
sqlite是一款优秀的单文件数据库软件,只需一个dll就就彻底包含数据库引擎的功能,并且能够嵌入至其它程序中,彻底不用额外的设定。其特性以下:
* 支持ACID (Atomic, Consistent, Isolated, Durable) 交易。
* 零组态设定(Zero-configuration),无须管理者的设定及管理。
* 支持大部分SQL92的语法。
* 数据库存在于一个单一的文件中。
* 数据库系统所在机器的字节顺序(Byte order)无关。
* 支援大小至2 TB (2^41 bytes)。
* 极小的内存需求:小于3万行的C语言程序代码。小于250KB的程序空间。
* 大部分的数据库操做皆快于通常流行的数据库系统。
* 简单易用的API。
* 支援TCL。也有其它语言的支持可用。
* 注释详细的程序代码,以及超过90%的测试。
* 连接库本身包含完整的功能,无须其它额外的程序或连接库。
* 程序代码版权为public domain。任何用途皆可无偿使用。
不过sqlite开源版是不支持加密的,只留有接口,没有进行实现,不过开源界历来不缺少雷锋,因而有了wxsqlite工程,wxsqlite是 sqlite的wxWidgets c++实现接口,顺便用aes加密算法实现了sqlite的加密功能,与sqlite 100%兼容,实在是赞!
我经常使用的数据库链接组件是unidac,最新的3.x版本已经支持sqlite,不过也没有实现加密函数定义,因而自已动手帮它加上,我用的版本是3.0.0.6。
\UniProviders\SQLite\LiteCallUni.pas是调用接口定义
// functions下面加上如下代码:
_sqlite3_key = function(
pDb: Tsqlite3; // Database handle
pKey: PAnsiChar; // Database PassWord (UTF-8)
nKey: Integer // Database sizeofpassword
): integer; {$IFNDEF CLR}cdecl;{$ENDIF}
_sqlite3_rekey = function(//If the current database is not encrypted, this routine will encrypt it. If pNew==0 or nNew==0, the database is decrypted.
pDb: Tsqlite3; // Database handle
pNew: PAnsiChar; // Database New PassWord (UTF-8)
nNew: Integer // Database sizeofnewpassword
): integer; {$IFNDEF CLR}cdecl;{$ENDIF}
...........................
var 下面加
sqlite3_key: _sqlite3_key;
sqlite3_rekey: _sqlite3_rekey;
........................................
procedure InitFunctions;
begin
{$IFDEF CLR}下面加
sqlite3_key := {$IFNDEF UNIDACPRO}LiteCallCLR{$ELSE}LiteCallCLRUni{$ENDIF}.sqlite3_key;
sqlite3_rekey := {$IFNDEF UNIDACPRO}LiteCallCLR{$ELSE}LiteCallCLRUni{$ENDIF}.sqlite3_rekey;
...................
{$ELSE}下面加
sqlite3_key := GetProc('sqlite3_key');
sqlite3_rekey := GetProc('sqlite3_rekey');
..................................
initialization
LockInit := TCriticalSection.Create;
{$IFNDEF CLR}下面加
sqlite3_key := @NotLink;
sqlite3_rekey := @NotLink;
..................................
\UniProviders\SQLite\LiteClassesUni.pas是引擎调用接口实现
Check(sqlite3_open(PAnsiChar(UTF8Encode(FDatabase)), FSQLite));
下面加:
if Pos('ChangePassword',FUsername)=1 then begin if Copy(FUsername,16,Length(FUsername))<>'' then SQLite3_key(FSQLite,PAnsiChar(Copy(FUsername,16,Length(FUsername))),SizeOf(FUsername)); if FPassword<>'' then SQLite3_rekey(FSQLite,PAnsiChar(FPassword),SizeOf(FPassword)); end else if FUsername='ClearPassword' then begin if FPassword<>'' then SQLite3_key(FSQLite,PAnsiChar(FPassword),SizeOf(FPassword)); SQLite3_rekey(FSQLite,0,0); end else if FPassword<>'' then Check(SQLite3_key(FSQLite,PAnsiChar(FPassword),SizeOf(FPassword)));
测试加密,解密正常。
用UniQuery添加数据
能够直接添加blob sub_type 1类型的字符串数据,以下面的text字段为blob sub_type 1.虽然UniTable也能够实现一样的功能,但因为其要载入全部记录内存,因此效率不是太好.而UniQuery.Params.ParamByName方法则不能直接添加blob sub_type 1类型的数据,也不能用loadfromstream(ms)进行加载数据,因此不行. procedure TForm1.FormCreate(Sender: TObject); begin self.UniConnection1.Connect; UniQuery1.Close; UniQuery1.SQL.Clear; UniQuery1.SQL.Text:='select * from tableblob where 0=1'; {返回空数据集,避免加载全部记录到内存,提升效率} UniQuery1.Open; UniQuery1.Prepared:=true; end; procedure TForm1.Button2Click(Sender: TObject); begin istart:=GetTickcount; //showmessage(inttostr(length(memo1.text))); //UniQuery1.Close; {若是字段内容超长,而且没有检查的话,须要close再open,才能保证下一条合法记录的添加,不然会再次报内容超长} //UniQuery1.open; UniQuery1.Append; UniQuery1.Fields.FieldByName('id').AsInteger:=GetMaxID1; UniQuery1.Fields.FieldByName('name').AsString:=Memo1.text; UniQuery1.Fields.FieldByName('text').AsString:=Memo2.Text; UniQuery1.Fields.FieldByName('datetime').AsDateTime:=Now; UniQuery1.Post; //UniQuery1.Transaction.Commit; {因为UniQuery是自动提交事务的,因此这句不须要} iend:=GetTickCount; caption:=floattostr((iend-istart)/1000); showmessage(UniQuery1.Fields.FieldByName('text').AsString); end;