第一章 ADO简介<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
1、原生ADO
OLE-DB定义了统一的COM接口作为存取各类异质数据源(关系数据库、Excel或其他文件)的标准,并且封装在COM对象之中。ADO对OLE-DB再次封装(因为OLE-DB太底层化)。
ADO架构为服务者、消费者模式。
2、Delphi中的ADO Express模型
第二章 ADOExpress介绍(一)
示例数据库为StudentCourse,有Student、Course、SC三个表。
1、基本组件介绍
(1)TADOConnection组件:
封装了原生ADO的Connection对象。提供了Pooling和Session管理功能。重要属性:ConnectionOptions(决定了异步还是同步方式连接)、IsolationLevel(代表ADO事务管理器所使用的事务IsolationLevel级别)、Mode(建立连接所允许的存取行为)。
(2)TADOCommand组件:
用来执行SQL中的数据定义语言(DDL),执行不回传结果集的SQL命令,占用资源较少。结果返回可以得用另外的DataSet接收。
(3)TADODataSet组件:
封装了ADO的RecordSet对象。重要的属性有CursorLocation、CursorType、LockType。而TADOStoredProc就是封装设定commandType为cmdStoredProc的RecordSet,TADOTable就是封装设定commandType为cmdTable的RecordSet。
TDataSet中的Open即设Active为True,Close即设Active为False。
通过分析SQLProfiler,当Open时:
1、SET FMTONLY ON select SC.Sno,Student.Sname,SC.Cno,Course.Cname,SC.score from Student,Course,SC where SC.Sno=Student.Sno and SC.Cno=Course.Cno SET FMTONLY OFF(先查询出列信息,不返回数据,只作一次)
2、select SC.Sno,Student.Sname,SC.Cno,Course.Cname,SC.score from Student,Course,SC where SC.Sno=Student.Sno and SC.Cno=Course.Cno(然后再返回数据信息)
2、MasterDetail型的设置(参见知识累积下面的MasterDetail项目)
通过从表的DataSource属性连接主表,从表的SQL含有参数,参数即主表的外码。
3、使用事务
代码模板:
Handle ADODataSet的BeforePost、AfterPost、PostError事件(这样每次Post的时候都会开启事务,当LockType为ltOptimistic时,只要游标改变就Post)。
procedure TForm1.ADODataSet1BeforePost(DataSet: TDataSet);
begin
self.ADOConnection1.BeginTrans;
end;
procedure TForm1.ADODataSet1AfterPost(DataSet: TDataSet);
begin
self.ADOConnection1.CommitTrans;
end;
procedure TForm1.ADODataSet1PostError(DataSet: TDataSet; E: EDatabaseError;
var Action: TDataAction);
begin
self.ADOConnection1.RollbackTrans;
Action:=daAbort;
end;
在SQL Server中首先set implicit_transactions on(如果前面已经开启,就不用执行)、然后执行语句:
exec sp_executesql N'UPDATE "StudentCourse".."SC" SET "score"=@P1 WHERE "score"=@P2 AND "SCNo"=@P3', N'@P1 int,@P2 int,@P3 varchar(10)', 12, 89, '2 '
如果执行成功:IF @@TRANCOUNT > 0 COMMIT TRAN;
执行不成功:IF @@TRANCOUNT > 0 ROLLBACK TRAN
当查询的时候自动结束:set implicit_transactions off
隐式事务:当连接以隐性事务模式进行操作时,Microsoft® SQL Server™ 将在提交或回滚当前事务后自动启动新事务。无须描述事务的开始,只需提交或回滚每个事务。隐性事务模式生成连续的事务链。(即所有的操作都以事务形式进行)。
小问题:当使用Refresh的时候,ADODataSet并不用我们赋给它的SQL语句,而是分析架构,自己分拆成多个SQL语句。在我的例子里三个表Join,数据集中两条记录,Refresh后生成6条select语句,即每个记录有三条(三个表两两Join进行select)。而其实只用一个Select就行了: select SC.Sno,Student.Sname,SC.Cno,Course.Cname,SC.score from Student,Course,SC where SC.Sno=Student.Sno and SC.Cno=Course.Cno。 而用Post自动更新的时候就会自动分析Join的关系,一条Update就搞定了。
4
、BatchUpdate 模式
将所有数据修改暂存于客户端缓存中,最后一次更新。
当locktype为ltBatchOptimistic时必须显示调用UpdateBatch(就算调Post都不行)即使Refresh也不会更新数据库。
UpdateBatch对多表连接也能自动更新,由于它是将更新分解,所以被更新的表必须有主码。更新的时候是按字段的顺序进行更新。
比如先更新Name字段的改变,然后再更新Score。
由于没有自动使用事务,所以前面的更改可能导致意料之外的错误。
分析自动生成的Update命令:
exec sp_executesql N'UPDATE "StudentCourse".."SC" SET "score"=@P1 WHERE "score"=@P2 AND "SCNo"=@P3', N'@P1 int,@P2 int,@P3 varchar(10)', 70, 65, '3 '
可见其不仅使用了主键作where同时还用了原字段的原有值。所以当将数据读到内存后,如果同时对数据源进行更改,再UpdateBatch时就会异常。
如果想取消更改,就用CancelBatch,注意:它是将缓冲中的旧值替换更改后的值,并不读数据库。
UpdateBatch也可以对视图进行更新。
关于乐观锁与悲观锁: 参见:http://www.cnblogs.com/zhenyulu/articles/208799.html 悲观锁的特点是:先加锁,再修改(读取),再保存,再解锁。悲观锁在记录级粒度上实现了"独占访问",解决了并发冲突的问题。同时,悲观锁锁定的记录越多,时间越长,资源的使用效率越低,给人的感觉就是性能越低下。 乐观缓冲模式的特点是:先修改(读取),再加锁,再保存,再解锁。也就是说乐观缓冲模式允许多人同时进行各自的修改操作(因为修改时不加锁),只有保存时才加锁,保存完后立刻解锁。因为用户修改数据往往占用较长的时间,而保存只是一瞬间的事,乐观缓冲模式可以保证锁定资源的时间尽可能的短,从而提高资源的使用效率。然而乐观缓冲模式的缺点就是无法避免并发冲突的发生。 如果出现A在缓冲中更改,同时B也更改,B更改完后已提交,如果A将更改提交就可能出现并发问题。 于是数据库字段含有三种值: OldValue:用户读出来的值 CurrentValue:数据库种的值 ProposedValue:用户更改后的值 ADO中自动生成的Update语句就考虑到了这些问题,所以有时候where中不仅仅含有主键,还含有被修改字段的原始数据(可以避免上述情况)。
在BatchUpdate下设置FilterGroup可以根据用户需要过滤数据(涉及各种修改、删除、添加的情况)。当然,必须先设置Filter为True再设置条件。
使用BatchUpdate就可以使用BriefCase编程模型,类似ADO.NET,将数据读出后SaveToFile存入文件中(有pfADTG、pfXML两种格式,当然存成XML了),断开连接。进行修改时先LoadFromFile读出,修改完后再打开连接,同时UpdateBatch。
注意:断开连接前要先置self.ADODataSet1.Connection:=nil;,否则关闭Connection的时候自动把ADODataSet的Active置False了,这样就不能编辑数据集了。
XML文件中先存储架构,然后存储每条记录,包括旧值新值。
5、搜寻数据
用ADODataSet的Locate或Lookup可以搜寻数据。
6、过滤数据
将Filtered设置为true就可以过滤,当然要设置过滤条件。
Filter:=条件
当过滤很复杂的条件的时候,就需要用编写过滤函数。
ADODataSet1.OnFilterRecord:=FilterRoutine;
FilterRoutine里通过设置Accept参数的True或False来决定该记录是否被过滤,OnFilterRecord是在检索每条记录的时候触发。
7、排序数据
ADO数据集的Sort属性可以实现排序