人生具有无限的可能性,你的梦想一定能实现

ADO指南

ADO 对象编程模型

  • 连接数据源 (Connection),可选择开始事务。
  • 可选择创建表示 SQL 命令的对象 (Command)。
  • 可选择指定列、表以及 SQL 命令中的值作为变量参数 (Parameter)。
  • 执行命令(Command、ConnectionRecordset)。
  • 如果命令以行返回,将行存储在存储对象中 (Recordset)。
  • 可选择创建存储对象的视图以便进行排序、筛选和定位数据 (Recordset)。
  • 编辑数据。可以添加、删除或更改行、列 (Recordset)。
  • 在适当情况下,可以使用存储对象中的变更对数据源进行更新 (Recordset)。
  • 在使用事务之后,可以接受或拒绝在事务中所做的更改。结束事务 (Connection)。

      步骤 1:打开连接

如果需要一种途径以建立交换数据所必须的条件,那就是“连接”。所连接的数据源可在“连接字符串”中指定,但是对于不同的提供者和数据源而言,连接字符串中指定的参数会有所不同。

ADO 打开连接的主要方法是使用 Connection.Open 方法。另外也可在同一个操作中调用快捷方法 Recordset.Open 打开连接并在该连接上发出命令。以下是 Visual Basic 中用于两种方法的语法:

connection.Open ConnectionString, UserID, Password, OpenOptions
recordset.Open Source, ActiveConnection, CursorType, LockType, Options

比较这两种方法将有益于加深对 ADO 方法操作数的总体了解。

ADO 提供了多种指定操作数的简便方式。例如:Recordset.Open 可带有 ActiveConnection 操作数,即文字字符串,它是代表字符串的变量或代表一个打开连接的 Connection 对象。

对象中的多数方法具有属性,当操作数缺省时属性可以提供参数。使用 Connection.Open,可以省略显式 ConnectionString 操作数并通过将 ConnectionString 的属性设置为“DSN=pubs;uid=sa;pwd=;database=pubs”隐式地提供信息。

与此相反,连接字符串中的关键字操作数 uidpwd 可为 Connection 对象设置 UserIDPassword 参数。

本教程使用显式连接字符串调用 Connection.Open 方法,数据源是“开放式数据库连接”(ODBC) pubs 数据库,它作为测试数据库与 Microsoft SQL Server 一同发布。(数据源的实际位置,如本地驱动器或远程服务器,在定义“数据源名称”(DSN) 时进行指定。)

connection.Open "DSN=pubs;uid=sa;pwd=;database=pubs"

步骤 2:创建命令

查询命令要求数据源返回含有所要求信息行的 Recordset 对象。命令通常使用 SQL 编写。

  1. 如上所述,“命令字符串”之类的操作数可表示为:
    • 代表字符串的文字串或变量。本教程可使用命令字符串“SELECT * from authors”查询 pubs 数据库中的 authors 表中的所有信息。
    • 代表命令字符串的对象。在这种情况下,Command 对象的 CommandText 属性的值设置为命令字符串。
      Command cmd = New ADODB.Command;
      cmd.CommandText = "SELECT * from authors"
      
  2. 使用占位符‘?’指定参数化命令字符串。

    尽管 SQL 字符串的内容是固定的,您也可以创建“参数化”命令,这样在命令执行时占位符‘?’子字符串将被参数所替代。

    使用 Prepared 属性可以优化参数化命令的性能,参数化命令可以重复使用,每次只需要改变参数。

    例如,执行以下命令字符串将对所有姓“Ringer”的作者进行查询:

    Command cmd = New ADODB.Command
    cmd.CommandText = "SELECT * from authors WHERE au_lname = ?"
    
  3. 指定 Parameter 对象并将其追加到 Parameter 集合。

    每个占位符‘?’将由 Command 对象 Parameter 集合中相应的 Parameter 对象值替代。 可将“Ringer”作为值来创建 Parameter 对象,然后将其追加到 Parameter 集合:

    Parameter prm = New ADODB.Parameter
    prm.Name = "au_lname"
    prm.Type = adVarChar
    prm.Direction = adInput
    prm.Size = 40
    prm.Value = "Ringer"
    cmd.Parameters.Append prm
    
  4. 使用 CreateParameter 方法指定并追加 Parameter 对象。

    ADO 现在可提供简易灵活的方法在单个步骤中创建 Parameter 对象并将其追加到 Parameter 集合。

    cmd.Parameters.Append cmd.CreateParameter _
    "au_lname", adVarChar, adInput, 40, "Ringer"
    

    本教程将不使用参数化命令,因为需要使用 Command.Execute 方法以参数替代占位符‘?’,但该方法不允许指定 Recordset 游标类型和锁定选项。为此将使用如下代码:

    Command cmd = New ADODB.Command;
    cmd.CommandText = "SELECT * from authors"
    步骤 3:执行命令

    返回 Recordset 的方法有三种:Connection.ExecuteCommand.Execute 以及 Recordset.Open。以下是它们的 Visual Basic 语法:

    connection.Execute(CommandText, RecordsAffected, Options)
    command.Execute(RecordsAffected, Parameters, Options)
    recordset.Open Source, ActiveConnection, CursorType, LockType, Options
    

    通过优化这些方法可发挥各自的优势。

    必须在发出命令之前打开连接,每种发出命令的方法代表不同的连接:

    • Connection.Execute 方法使用由 Connection 对象自身表现的连接。
    • Command.Execute 方法使用在其 ActiveConnection 属性中设置的 Connection 对象。
    • Recordset.Open 方法所指定的或者是连接字符串,或者是 Connection 对象操作数;否则使用在其 ActiveConnection 属性中设置的 Connection 对象。

    另一个不同点是命令在三种方法中的指定方式:

    • Connection.Execute 方法中,命令是字符串。
    • Command.Execute 方法中,命令是不可见的,它在 Command.Command — Text 属性中指定。另外,此命令可含有参数符号 ('?'),它可以由“参数”VARIANT 数组参数中的相应参数替代。
    • Recordset.Open 方法中,命令是 Source 参数,它可以是字符串或 Command 对象。

    每种方法可根据性能需要替换使用:

    • Execute 方法针对(但不局限)于执行不返回数据的命令。
    • 两种 Execute 方法都可返回快速只读、仅向前 Recordset 对象。
    • Command.Execute 方法允许使用可高效重复利用的参数化命令。
    • 另一方面,Open 方法允许指定 CursorType (用于访问数据的策略及对象)和 LockType (指定其他用户的 isolation 级别以及游标是否在 immediatebatch modes 中支持更新)。

    请深入了解这些选项,它们在很大程度上体现了 Recordset 的功能。

    本教程使用动态游标对 Recordset 的所有变更进行批处理,请使用以下方法:

    Recordset rs = New ADODB.Recordset
    rs.Open cmd, conn, adOpenDymanic, adLockBatchOptimistic
    步骤 4:操作数据

    大量 Recordset 对象方法和属性可用于对 Recordset 数据行进行检查、定位以及操作。

    Recordset 可看作行数组,在任意给定时间可进行测试和操作的行为“当前行”,在 Recordset 中的位置为“当前行位置”。每次移动到另一行时,该行将成为新的当前行。

    有多种方法可在 Recordset 中显式移动或“定位”(Move 方法)。一些方法(Find 方法)在其操作的附加效果中也能够做到。此外,设置某个属性(Bookmark 属性)同样可以更改行的位置。

    Filter 属性用于控制可访问的行(即这些行是“可见的”)。Sort 属性用于控制所定位的 Recordset 行中的顺序。

    Recordset 有一个 Fields 集合,它是在行中代表每个字段或列的 Field 集,可从 Field 对象 的 Value 属性中为字段赋值或检索数据。作为选项,可访问大量字段数据(GetRowsUpdate 方法)。

    在本教程中,您将要:

    • 将假设区号为“415”、局号以“5”开头的电话号码区号改为“777”。
    • 设置 au_lname Field 对象的 Optimize 属性以提高存储和筛选性能。
    • 按作者的姓将 Recordset 排序。
    • 筛选 Recordset,使作者电话区号为“415”、局号为“5”的行成为仅可访问(即可见)的行。

    使用 Move 方法从头至尾对经过排序和筛选的 Recordset 定位。当 Recordset EOF 属性表明已经到达最后一行时停止。在 Recordset 中移动时,显示作者的姓和名以及原始电话号码,然后将 phone 字段中的区号改为“777”。(phone 字段中的电话号码属于窗体“aaa xxx-yyyy”,其中 aaa 为区号,xxx 为局号。)

    rs!au_lname.Optimize = TRUE
    rs.Sort = "au_lname ASCENDING"
    rs.Filter = "phone LIKE '415 5*'"
    rs.MoveFirst
    Do While Not rs.EOF
       Debug.Print "Name: " & rs!au_fname & " " rs!au_lname & _
          "Phone: " rs!phone & vbCr
       rs!phone = "777" & Mid(rs!phone, 5, 11)
       rs.MoveNext
    Loop
    步骤 5:更新数据

    您刚刚对 Recordset 若干行中的数据进行了修改,ADO 有两种基本途径用于添加、删除和修改数据行。

    其一是更改不是立即对 Recordset 进行而是对“复制缓冲区”进行,当您不想更改时,复制缓冲区中的改动将被放弃;如果想保留更改,复制缓冲区中的改动将应用于 Recordset

    其二是当您声明行的工作已经完成时(即“立即”模式)将更改立刻传给数据源,否则将收集对行集合的所有更改,直到您声明该行集合的工作已经完成(即“批”模式)。这些模式将由 CursorLocationLockType 属性加以控制。

    在“立即”模式中,每个 Update 方法的调用都将更改传送给数据源,而在“批”模式中,虽然每个 Update 调用和当前行位置移动都将更改存放在 Recordset 中,但只有 UpdateBatch 方法才可将更改传送给数据源。由于打开 Recordset 使用的是批模式,因此更新也使用批模式。

    注意    Update 可采用简捷的形式将更改用于单个字段或将一组更改用于一组字段,然后再进行更改,这样可以一步完成更新操作。

    可选择在“事务”中进行更新。实际上,您可以使用事务来确保多个相互关联的操作或者全部成功执行,或者全部取消。在此情况下,事务不是必须的。

    事务可在一段相当长的时间内分配和保持数据源上的有限资源,因此建议事务的存在时间越短越好。(这便是本教程不在进行连接之初就开始事务的原因。)

    为使用教程,将您的批更新括在事务中:

    conn.BeginTrans
    rs.UpdateBatch
    ...
    步骤 6:结束更新

    假设批更新中含有错误,错误的解决则取决于错误的性质和严重性以及应用程序的逻辑关系。如果数据库是与其他用户共享的,典型的错误则是他人在您之前更改了数据字段,这种类型的错误称为“冲突”。ADO 将检测到这种请况并报告错误。

    在本教程中,这个步骤分为两部分:如果不存在更新错误则“提交”事务,结束更新。

    如果错误存在,它们会被错误处理例程捕获。可使用 adFilterConflictingRecords 常数对 Recordset 进行筛选,将冲突行显示出来。要纠正错误只需打印作者的姓和名(au_fnameau_lname),然后回卷事务,放弃成功的更新。由此结束更新。

    ...
    conn.CommitTrans
    ...
    On Error
    rs.Filter = adFilterConflictingRecords
    rs.MoveFirst
    Do While Not rs.EOF
       Debug.Print "Conflict: Name: " & rs!au_fname " " & rs!au_lname
       rs.MoveNext
    Loop
    conn.Rollback
    Resume Next
    ...
    
posted @ 2011-01-20 23:42  代号极光  阅读(267)  评论(0编辑  收藏  举报

本博客所有权归作者代号极光紫竹园博客园