delphi uniDac

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;
View Code

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;
View Code

對於單數據集的提交:
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;
View Code

--無返回值的插入數據

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');
View Code

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';就執行報錯
 
View Code

基於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.
View Code

三、給出使用鏈接池的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
View Code

實現代碼:

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.
View Code

 

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;
View Code

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;
View Code

對於單數據集的提交:
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;
View Code

直連模式(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;
View Code

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.
View Code

 

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.
View Code

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;
View Code

須要注意的是,必須先判斷鏈接控件 (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.
View Code

有網友問我經常使用的控件及功能。我先大概整理一下,之後會在文章裏面碰到時再仔細介紹。
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)));
View Code

測試加密,解密正常。

用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;
 
View Code
相關文章
相關標籤/搜索