步骤 3:重用组件

目标

在本步骤中,您将了解以下内容:

  • 可重复使用的组件。
  • 如何计划可重用性。

说明

此 COM+ 服务入门的前两部分(即步骤 1:创建事务组件步骤 2:跨多个组件扩展事务)演示了如何编写一个组件来调用第二个组件,以便帮助完成某些工作,更新 Microsoft SQL Server Pubs 数据库中的作者信息;所有工作都受单个事务的保护。 示例组件侧重于更新作者数据以及验证作者地址的工作,以及 COM+ 提供的事务处理、JIT 激活并发保护

此步骤演示如何重用步骤 1 和 2 中创建的组件,并了解这些组件的设计意味着什么。 如下图所示,这意味着创建新的组件 AddNewAuthor,以通过调用 UpdateAuthorAddress 将新作者添加到数据库。

Diagram that shows the flow when reusing components.

除了重用现有组件功能外,AddNewAuthor 还将调用另一个名为 ValidateAuthorName 的新组件。 如上图所示,ValidateAuthorName 是非事务组件。 此组件的事务属性值保留在其默认设置 (Not Supported),以从事务中排除其工作。 如步骤 3 示例代码所示,ValidateAuthorName 会对数据库执行只读查询,此次要任务的失败不可能中止事务。 但是,AddNewAuthor 组件的事务属性值设置为 Required

AddNewAuthorUpdateAuthorAddressValidateAuthorAddress 组件都在事务中投票。 在此事务中,AddNewAuthor 是根对象。 COM+ 始终将在事务中创建的第一个对象设为根对象。

在此示例中,重用 UpdateAuthorAddress 组件非常简单 - COM+ 会自动提供预期服务。 但是,如果最初将 UpdateAuthorAddress 组件的事务属性值设置为 Requires New,而不是 Required,则结果会有所不同。 在表面上,这两个设置看起来相似;这两者都保证事务。 但是,Requires New 始终启动一个新事务,而 Required 仅在对象的调用方为非事务调用方时才启动新事务。 从中可以看到,仔细和深思熟虑地配置 UpdateAuthorAddress 是多么重要。 否则,COM+ 可能会以不同的方式解释服务请求,从而生成两个不相关的事务(如下图所示),而不是一个。

Diagram that shows the flow when reusing components with

注意

重复使用组件时,请确保将服务配置为支持所需结果。

 

示例代码

AddNewAuthor 组件允许对象保持活动状态,直到客户端释放对对象的引用,从而执行新作者的批处理添加。

Option Explicit
'
'   Purpose:   This class is used for adding a new author.
'
'   Notes:    IMPT:  This component implicitly assumes that it will
'             always run in a transaction. Undefined results may 
'             otherwise occur.
'
'  AddNewAuthor
'
Public Sub AddNewAuthor( _
                        ByVal strAuthorFirstName As String, _
                        ByVal strAuthorLastName As String, _
                        ByVal strPhone As String, _
                        ByVal strAddress As String, _
                        ByVal strCity As String, _
                        ByVal strState As String, _
                        ByVal strZip As String, _
                        ByVal boolContracted As Boolean)
  ' Handle any errors.
  On Error GoTo UnexpectedError

  ' Verify component is in a transaction.
  ' The VerifyInTxn subroutine is described in Step 1.
  VerifyInTxn

  ' Get our object context.
  Dim objcontext As COMSVCSLib.ObjectContext
  Set objcontext = GetObjectContext

  ' Get the IContextState object.
  Dim contextstate As COMSVCSLib.IContextState
  Set contextstate = objcontext

  ' Validate that the author is OK.
  ' The ValidateAuthorName function is described after this function.
  Dim oValidateAuthName As Object
  Dim bValidAuthor As Boolean
  Set oValidateAuthName = CreateObject("ComplusPrimer.ValidateAuthorName")
  bValidAuthor = oValidateAuthName.ValidateAuthorName( _
    strAuthorFirstName, strAuthorLastName)
  If Not bValidAuthor Then
    Err.Raise 999999, "The AddNewAuthor component", _
      "You tried to add an author on the banned list!"
  End If
  
  ' Open the connection to the database.
  Dim conn As ADODB.Connection
  Set conn = CreateObject("ADODB.Connection")

  ' Specify the OLE DB provider.
  conn.Provider = "SQLOLEDB"

  ' Connect using Windows Authentication.
  Dim strProv As String
  strProv = "Server=MyDBServer;Database=pubs;Trusted_Connection=yes"

  ' Open the database.
  conn.Open strProv

  ' Tell the database to actually add the author; use empty strings 
  ' for this part and rely on the UpdateAuthorAddress 
  ' component to validate the address/phone/etc data.
  ' Default Contract flag is off.
  Dim strUpdateString As String
  strUpdateString = "insert into authors values(_
                     '789-65-1234'," & _
                     strAuthorLastName & ", " & _
                     strAuthorFirstName & ", " & _
                     "'(555) 555-5555', ', ', ', '98765', "

  If boolContracted Then
    strUpdateString = strUpdateString + "1)"
  Else
    strUpdateString = strUpdateString + "0)"
  End If

  conn.Execute strUpdateString
  
  ' Close the connection; this potentially allows 
  ' another component in the same transaction to
  ' reuse the connection from the connection pool.
  conn.Close
  Set conn = Nothing
  
  ' Create the UpdateAuthorAddress component.
  Dim oUpdateAuthAddr As Object
  Set oUpdateAuthAddr = CreateObject("ComplusPrimer.UpdateAuthorAddress")
  
  ' The component throws an error if anything goes wrong.
  oUpdateAuthAddr.UpdateAuthorAddress "", strPhone, _
    strAddress, strCity, strState, strZip
    
  Set oUpdateAuthAddr = Nothing
  
  ' Everything works--commit the transaction.
  contextstate.SetMyTransactionVote TxCommit
  
  '  Design issue:  Allow batch additions of new
  '  authors in one transaction, or should each new author be added
  '  in a single new transaction?
  contextstate.SetDeactivateOnReturn False
  Exit Sub
  
UnexpectedError:
  ' There's an error.
  contextstate.SetMyTransactionVote TxAbort
  contextstate.SetDeactivateOnReturn True
  
End Sub

AddNewAuthor 将名称添加到数据库之前,ValidateAuthorName 组件会验证作者名称。 如果发生意外情况,此组件会向调用方抛出错误。

Option Explicit
'
'   Purpose:   This class is used for validating authors before
'              adding them to the database.
'
'   Notes:   This component doesn't need to be in a transaction because
'            it is performing read-only queries on the database,
'            especially since these queries are not overlapping with
'            any updates of end-user data. If an unexpected error
'            happens, let the error go back to the caller who
'            needs to handle it.
'

Public Function ValidateAuthorName( _
                        ByVal strAuthorFirstName As String, _
                        ByVal strAuthorLastName As String _
                        ) As Boolean
  ValidateAuthorName = False

  ' Open the connection to the database.
  Dim conn As ADODB.Connection
  Set conn = CreateObject("ADODB.Connection")

  ' Specify the OLE DB provider.
  conn.Provider = "SQLOLEDB"

  ' Connect using Windows Authentication.
  Dim strProv As String
  strProv = "Server=MyDBServer;Database=pubs;Trusted_Connection=yes"

  ' Open the database.
  conn.Open strProv

  ' Suppose another hypothetical table has been added to the Pubs 
  ' database, one that contains a list of banned authors.
  Dim rs As ADODB.Recordset
  Set rs = conn.Execute("select * from banned_authors")
  
  ' Loop through the banned-author list looking for the specified
  ' author.
  While Not rs.EOF
    If rs.Fields("FirstName") = strAuthorFirstName And _
      rs.Fields("LastName") = strAuthorLastName Then
        ' This is a banned author.
        conn.Close
        Set conn = Nothing
        Set rs = Nothing
        Exit Function
    End If
    rs.MoveNext
  Wend
  
  ' None of the added authors found in the banned list.
  ValidateAuthorName = True
  conn.Close
  Set conn = Nothing
  Set rs = Nothing
End Function

总结

  • 有时,不希望组件在事务中投票。
  • COM+ 不会对非事务组件强制实施 JIT 激活或并发保护。 可以单独配置这些服务。
  • 调用组件的配置会影响 COM+ 如何解释所调用组件的服务请求。

步骤 1:创建事务组件

步骤 2:跨多个组件扩展事务

配置事务

针对可伸缩性进行设计