Delphi 原生ADO(二)

我发现很多朋友在开发数据库时都使用 Delphi 自带的 ADO 组 件 或 Diamond ADO,其实在 Delphi 中使用原生 ADO 接口也是十分方便和有效的。我使用原生 ADO 开发项目已有很长一段时 间,也回答过一些朋友类似的问题,现在把自己的一点心得与大家分享,班门弄斧,只是希望能对大家有所帮助。当然,这帖子也是原生的,不是转贴的。

一、优点
1、
大家知道 Delphi 对 ADO 接口进行了一番包装后形成了 ADOExpress,我想 Borland 的主要目的还是想与自己的数据敏感控件
相连。然而事实上数据敏感控件并不是那么耀眼,如果你希望你编出来的程序稍微有点水准的话那就别用那玩意;如果你很少使用数据敏感控件,那
么 ADOExpress 基本上失去了其应有的作用,无数冗余的属性、虚方法,不管你用不用得到一股脑给你编译进去,也会使你的程序再大上 200K;
效率么,不说了。
2、MSDN 和 VB 中的例子你可以搬过来就用。
3、告诉那些 Delphi 反对者,Delphi 不是离开组件就活不了。
4、关于代码重用:我给大家的例子都是以函数或过程形式,重用性不好么?
5、别说帖子太长,那你看看 DB.pas, ADODB.pas 多长?

二、基本储备
1、一些必须的单元
uses
   Variants, ComObj;

2、一些基本常数(其它查 ADODB2000.pas):

const
   adOpenDynamic = $00000002;
   adOpenStatic = $00000003;

   adLockOptimistic = $00000003;
   adLockBatchOptimistic = $00000004;

   adStateClosed = $00000000;
   adStateOpen = $00000001;
   adStateConnecting = $00000002;
   adStateExecuting = $00000004;
   adStateFetching = $00000008;

   adUseServer = $00000002;
   adUseClient = $00000003;

   adModeReadWrite = $00000003;

   adXactCursorStability = $00001000;

   adCmdText = $00000001;
   adCmdTable = $00000002;
   adCmdStoredProc = $00000004;
   adCmdFile = $00000100;

   adAffectCurrent = $00000001;
   adAffectGroup = $00000002;
   adAffectAll = $00000003;
   adAffectAllChapters = $00000004;

3、一些基本函数和过程
//创建 Connection 对象
function CreateConnection: OleVariant;
//释放 Connection 对象;cnn 为 Connection 对象
procedure FreeConnection(var cnn: OleVariant);
//创建 Recordset 对象
function CreateRecordset: OleVariant;
//释放 Recordset 对象;rst 为 Recordset 对象
procedure FreeRecordset(var rst: OleVariant);
//创建 Command 对象
function CreateCommand: OleVariant;
//释放 Command 对象;cmd 为 Command 对象
procedure FreeCommand(var cmd: OleVariant);
//用 Connection 连接到 SQLServer 数据库;cnn 为 Connection 对象,db 数据库名,host 主机名,usr 用户名,pwd 密码
function ConnectToDB(cnn: OleVariant; const db, host, usr, pwd: string): Boolean;
//执行 SQL 语句,有返回行,无事务处理;cnn 为 Connection 对象,rst 为 Recordset 对象,sql 为 SQL 语句(可以是存储过程)
function ExecSQL(cnn, rst: OleVariant; const sql: string): Boolean;
//执行 SQL 语句,无返回行,有事务处理;cnn 为 Connection 对象,cmd 为 Command 对象,sql 为 SQL 语句(可以是存储过程)
function ExecSQLA(cnn, cmd: OleVariant; const sql: string): Boolean;

function CreateConnection: OleVariant;
begin
   try
     Result := CreateOleObject(‘ADODB.Connection‘);
     Result.CursorLocation := adUseServer;
     Result.IsolationLevel := adXactCursorStability;
     Result.Mode := adModeReadWrite;
     Result.Provider := ‘SQLOLEDB.1‘;
   except
     if not VarIsEmpty(Result) then Result := Unassigned;
   end;
end;

procedure FreeConnection(var cnn: OleVariant);
begin
   if not VarIsEmpty(cnn) then
   begin
     if cnn.State <> adStateClosed then cnn.Close;
     cnn := Unassigned;
   end;
end;

function CreateRecordset: OleVariant;
begin
   try
     Result := CreateOleObject(‘ADODB.Recordset‘);
     Result.CacheSize := 1000;
     Result.CursorType := adOpenStatic;
     Result.CursorLocation := adUseServer;
     Result.LockType := adLockOptimistic;
   except
     if not VarIsEmpty(Result) then Result := Unassigned;
   end;
end;

procedure FreeRecordset(var rst: OleVariant);
begin
   FreeConnection(rst);
end;

function CreateCommand: OleVariant;
begin
   try
     Result := CreateOleObject(‘ADODB.Command‘);
     Result.CommandType := adCmdText;
     Result.CommandTimeout := 5;
   except
     if not VarIsEmpty(Result) then Result := Unassigned;
   end;
end;

procedure FreeCommand(var cmd: OleVariant);
begin
   if not VarIsEmpty(cmd) then cmd := Unassigned;
end;

function ConnectToDB(cnn: OleVariant; const db, host, usr, pwd: string): Boolean;
begin
   Result := not VarIsEmpty(cnn);
   if Result then
   begin
     if cnn.State <> adStateClosed then cnn.Close;
     cnn.ConnectionString :=
       ‘Provider=SQLOLEDB.1;Persist Security Info=True;Initial Catalog=‘ +
       db + ‘;Data Source=‘ + host + ‘;Connect Timeout=5;‘ +
       ‘Use Procedure for Prepare=1‘;
     try
       cnn.Open(cnn.ConnectionString, usr, pwd, -1);
     except
       Result := False;
     end;
   end;
end;

function ExecSQL(cnn, rst: OleVariant; const sql: string): Boolean;
begin
   Result := not (VarIsEmpty(cnn) or VarIsEmpty(rst)) and (cnn.State = adStateOpen);
   if Result then
   begin
     if rst.State <> adStateClosed then rst.Close;
     try
       rst.Open(sql, cnn, adOpenStatic, adLockOptimistic, adCmdText);
     except
       Result := False;
     end;
   end;
end;

function ExecSQLA(cnn, cmd: OleVariant; const sql: string): Boolean;
begin
   Result := not (VarIsEmpty(cnn) or VarIsEmpty(cmd)) and (cnn.State = adStateOpen);
   if Result then
   begin
     cnn.BeginTrans;
     try
       cmd.ActiveConnection := cnn;
       cmd.CommandText := sql;
       cmd.Prepared := True;
       cmd.Execute;
       cnn.CommitTrans;
     except
       cnn.RollbackTrans;
       Result := False;
     end;
   end;
end;

三、访问数据
1、最前 rst.MoveFirst;
2、最后 rst.MoveLast;
3、向前 rst.MovePrevious;
4、向后 rst.MoveNext;
5、取当前记录 rst.Fields[0].Value 或 rst.Fields[‘字段名‘].Value;
6、修改当前记录 rst.Update(rst.Fields[0].Name, 某值);
7、取消修改 rst.CancelUpdate;
8、删除当前记录 rst.Delete(adAffectCurrent);
9、删除所有记录 rst.Delete(adAffectAll);
10、追加记录
   rst.AddNew;
   rst.Fields[0].Value := 值1;
   rst.Fields[1].Value := 值2;
   rst.Update;
11、刷新 rst.Refresh;
12、记录数 rst.RecordCount
15、其它方法和属性查 MSDN 或 ADO 的帮助;

四、一些例子

//变量声明
var
   cnn, rst, cmd: OleVariant;

//创建对象
procedure TForm1.FormCreate(Sender: TObject);
begin
   cnn := CreateConnection;
   rst := CreateRecordset;
   cmd := CreateCommand;
end;

//释放对象
procedure TForm1.FormDestroy(Sender: TObject);
begin
   FreeCommand(cmd);
   FreeRecordset(rst);
   FreeConnection(cnn);
end;

//连接数据库
procedure TForm1.Button1Click(Sender: TObject);
begin
   if ConnectToDB(cnn, ‘mydb‘, ‘127.0.0.1‘, ‘sa‘, ‘ok‘) then
     Caption := ‘连接成功‘
   else Caption := ‘连接失败‘;
end;

//取记录
procedure TForm1.Button2Click(Sender: TObject);
begin
   ExecSQL(cnn, rst, ‘select * from 表a‘);
   Caption := VarToStr(rst.Fields[‘字段a‘].Value);
end;

五、原生 ADO 与 Delphi ADOExpress 组件的对应关系
1、Connection <=> ADOConnection.ConnectionObject;
2、Recordset <=> ADODataSet.Recordset;
3、Command <=> ADOCommand.CommandObject;
4、? <=> ADOQuery,因为 ADOQuery 根本就不是原生 ADO 对象 
5、ExecSQL <=> ADODataSet.Open;
6、ExecSQLA <=> ADOCommand.Execute;
7、有了上面几个其它的就不多说了

六、与数据库结构有关的一些函数
1、动态改变字段名称

uses ComObj;
//Access
//TableName: 表名; OldColName: 原字段名; NewColName: 新字段名;
procedure RenameField(const TableName, OldColName, NewColName: string);
var
   DB, Col: OleVariant;
begin
   DB := CreateOleObject(‘ADOX.Catalog‘);
   DB.ActiveConnection := ADOConnection1.ConnectionObject;
   Col := CreateOleObject(‘ADOX.Column‘);
   Col := DB.Tables[TableName].Columns[OldColName];
   Col.Name := NewColName;
end;

//SQLServer
procedure RenameField(const TableName, OldColName, NewColName: string);
begin
   with ADOCommand1 do
   begin
     CommandText := ‘EXEC sp_rename ‘‘‘ + TableName + ‘.‘ + OldColName +
       ‘‘‘,‘‘‘ + NewColName + ‘‘‘,‘‘COLUMN‘‘;‘;
     Excute;
   end;
end;

2、取得 Access 库中的表结构
type
   TTableDef = record
     Name,
     DateCreated,
     LastUpdated,
     Description: string;
   end;

   TTableDefs = array of TTableDef;

procedure GetTableDefs(const DBName: string; out TableDefs: TTableDefs);
var
   DBEngine, DB: OleVariant;
   I: Longint;
begin
   try
     DBEngine := CreateOleObject(‘DAO.DBEngine.36‘);
     DB := DBEngine.OpenDatabase(DBName);
     SetLength(TableDefs, Longint(DB.TableDefs.Count));
     for I := Low(TableDefs) to High(TableDefs) do
     begin
       TableDefs[I].Name := DB.TableDefs[I].Name;
       TableDefs[I].DateCreated := DB.TableDefs[I].DateCreated;
       TableDefs[I].LastUpdated := DB.TableDefs[I].LastUpdated;
       try
         TableDefs[I].Description := DB.TableDefs[I].Properties[‘Description‘].Value;
       except
         TableDefs[I].Description := ‘‘;
       end;
     end;
   finally
     DB := Unassigned;
     DBEngine := Unassigned;
   end;
end;

3、取得 Access 表中的字段结构
type
   TFieldDef = record
     Name: string;
     Types,
     Size: Longint;
     Description: string;
   end;

   TFieldDefs = array of TFieldDef;

procedure GetFieldDefs(const DBName, TableName: string; out FieldDefs: TFieldDefs);
var
   DBEngine, DB: OleVariant;
   I: Longint;
begin
   try
     DBEngine := CreateOleObject(‘DAO.DBEngine.36‘);
     DB := DBEngine.OpenDatabase(DBName);
     SetLength(FieldDefs, Longint(DB.TableDefs[TableName].Fields.Count));
     for I := Low(FieldDefs) to High(FieldDefs) do
     begin
       FieldDefs[I].Name := DB.TableDefs[TableName].Fields[I].Name;
       FieldDefs[I].Types := DB.TableDefs[TableName].Fields[I].Type;
       FieldDefs[I].Size := DB.TableDefs[TableName].Fields[I].Size;
       try
         FieldDefs[I].Description := DB.TableDefs[TableName].Fields[I].Properties[‘Description‘].Value;
       except
         FieldDefs[I].Description := ‘‘;
       end;
     end;
   finally
     DB := Unassigned;
     DBEngine := Unassigned;
   end;
end;

4、至于如何动态创建 Access 数据库之类我就不罗嗦了,到处都有相关的月经贴

七、其它
1、我使用 ADO 的经历:ADOExpress-->ADOExpress的原生接口-->引用ADO2.1接口单元,即ADODB_TLB-->直接使用 ADO 的 COM 接口;
2、希望此贴能对朋友门有所帮助,我写的这些都是经过实战检验的;
3、觉得有用的朋友可以试一下,如果觉得没用就当我没写,耽误你时间了。

时间: 2024-08-02 20:11:28

Delphi 原生ADO(二)的相关文章

Delphi通过ADO读写数据库

ADO是一种程序对象,用于表示用户数据库中的数据结构和所包含的数据. ADO (ActiveX Data Objects,ActiveX数据对象)是Microsoft提出的应用程序接口(API)用以实现访问关系或非关系数据库中的数据.例如,如果您希望编写应用程序从DB2或Oracle数据库中向网页提供数据,可以将ADO程序包括在作为活动服务器页(ASP)的HTML文件中.当用户从网站请求网页时,返回的网页也包括了数据中的相应数据,这些是由于使用了ADO代码的结果. 在Delphi 5.0 以上的

升讯威ADO.NET增强组件(源码):送给喜欢原生ADO.NET的你

不提码代码,光是写博客就要写一整个晚上,对您有用的话还请赞一个~ 目前我们所接触到的许多项目开发,大多数都应用了 ORM 技术来实现与数据库的交互,ORM 虽然有诸多好处,但是在实际工作中,特别是在大型项目开发中,容易发现 ORM 存在一些缺点,在复杂场景下,反而容易大大增加开发的复杂度及牺牲灵活度.使用 ORM 不写 SQL 而使数据库交互变得简单易行,是否能够达到预期效果,要画一个问号. 主要问题可能存在于以下几点: 1.大幅度牺牲性能. 2.虽然隐藏了数据层面的设计,但并没有从根本上降低数

Delphi中ADO异步执行方式

当ADO开始处理数据后,应用程序必须等到ADO处理完毕之后才可以继续执行.但是除了同步执行方式之外,ADO也提供了异步执行的方式,允许当ADO处理时,应用程序仍然能够先继续执行.而当ADO处理数据完毕之后,ADO会以事件的方式通知应用程序,此时应用程序可以再根据ADO执行的结果来采取相应的动作.使用异步执行方式有许多用途,例如,如果应用程序需要处理花费大量时间的动作,那么ADO可以选择以异步执行方式让ADO在后台执行,而让应用程序继续处理图形用户接口或用户输入的数据.在ADO中使用异步执行方式非

delphi 基础之二 面向对象概念初步

面向对象概念初步 1.类的定义 类的定义分两步:首先在类(单元)的接口(interface)部分说明这个方法.然后在实现部分(implementation)部分编写方法的实现代码. 定义: type 类名=class(父类名) 数据域说明;      //类内部使用变量/常量的声明; 方法说明首部; end; 实现代码: procedure 类名.方法(参数); 实现代码; end; 2.创建对象及对象成员的引用 创建对象分两步: 首先声明对象,语法格式为 var 类名;//此时对象名还只是个指

纯Delphi 原生写的 上传到七牛的功能

上传文件到七牛, 支持分片分段上传, 适用于Delphi XE, 10等新版本 分两个函数: uploadToQiniu 和 directUploadToQiniu uploadToQiniu 这个函数使用分片, 分段的方式上传, 并有上传进度回调, 采用多线程同时进行, 该方法适用于上传较大文件. directUploadToQiniu 该函数直接使用Form表单的形式上传, 没有上传进度回调, 适用于上传较小的文件. 上面两个方法已经使用于 好智学项目中, 被大量用户实际验证可行. 具体代码

Delphi 通过ADO连接数据库

原文地址:https://www.cnblogs.com/fanweisheng/p/11385205.html

二维码生成delphi版

二维码生成delphi版 生成二维码的软件,代码从C语言转换过来(源地址:http://fukuchi.org/works/qrencode/),断断续续的差不多花了一周时间来转换和调试.在转换过程中学到了不少东西,特别是对于delphi和C语言中一些概念比较模糊的地方,有了更清楚地认识. 支持中英文文字生成二维码,在手机上使用快拍和微信扫描后显示正常,无乱码.在delphi 7 / delphi 2010 / delphi XE5上调试通过.qrencode的源代码为C语言,支持生成png格式

写了一个关于《Delphi二维码、分组、批量》的帖子

Delphi二维码 分组批量打印delphi二维码分组批量打印Delphi二维码中文支持.分组.批量打印经验小结FastReport设计入库单报表实例 Delphi 二维码 分组批量打印 fastreport 控件 背景:一直也没接触到什么复杂的报表,都是一些简单的报表,在DelphI下使用QuickReport一般也就能满足需要了,由于公司现在需求的变化,对条码扫描提出了新的要求,主要是扫码要包含更多地内容,以前的一维码显然不能完全满足,再说二维码也是一种趋势,故而需要解决二维码的问题,网上搜

DELPHI XE5 与SQLITE

最近一次使用DELPHI做项目是使用DELPHI2009,为了访问本地数据库方便,使用ACCESS数据库,不需要安装驱动,(WINDOWS自带),但是ACCESS数据库的性能确实很糟糕,通过ADO连接,INSERT 1000条数据平均在1.5秒以上. 面前面临一个新的项目,本地数据库是继续用ADO,还是其他,成了一个问题. 近期比较流行的本地数据库是SQLite,想测试下SQLite的性能,和方便程度. 1. DELPHI 和 SQLITE在度娘上提的最多的是通过ASQLite3DB组件进行连接