在 SOAP 会话中使用事务

后续版本的 Microsoft SQL Server 将删除该功能。 请避免在新的开发工作中使用该功能,并着手修改当前还在使用该功能的应用程序。

事务通常由一系列依次提交并需要按顺序执行的批处理构成。如果事务中的任何批处理没有完成,事务将回滚,撤消事务作用域内较早的批处理所做的更改并将受影响的数据还原到其以前的状态。

在传统 SQL 数据访问中,处理和执行由多个批处理构成的事务时,依靠基础网络连接为事务中的所有批处理提供服务。例如,下列示例说明了 SQL Server 连接和三个不同事务间的关系:

SQL connection(1)
     --> SQL batch(1)
          --> transaction(1)
     --> SQL batch(2)
          --> transaction(2a)
     --> SQL batch(3)
          --> transaction(2b), transaction(3)

请注意,将执行事务 (1) 和 (3) 并将它们包含在相同的批处理中进行提交;但事务 (2) 将扩展到批处理 (2) 和 (3) 中。基础连接提供上下文,确保事务按所需的顺序执行所有批处理。对于 HTTP SOAP 访问,使用单个基础网络连接的上下文不能执行事务处理。因此,若要支持由多个批处理构成的事务的处理,单个 SOAP 会话可起到相同的作用。例如,下列代码说明相同的批处理和事务模式在 HTTP SOAP 访问下如何执行。

SOAP session(1)
     --> SQL batch(1)
          --> transaction(1)
     --> SQL batch(2)
          --> transaction(2a)
     --> SQL batch(3)
          --> transaction(2b), transaction(3)

只要同一个 SOAP 会话 (1) 保持活动状态,通过将该会话用作基础上下文,就可以在单独的 SOAP 请求/响应消息对中执行每个批处理。

SQL Server 如何管理基于 SOAP 的事务

当事务状态发生更改时,将在 SQL Server 实例中启动 SQL 事务。由于服务器处理来自客户端的 SOAP 请求而产生下列任何事件都可能会引起这种情况:

  • 开始事务

  • 提交事务

  • 回滚事务

  • DTC 在事务中登记

  • DTC 从事务中脱离

默认情况下,服务器在自动提交事务模式下操作。此行为使用相当简单的一对一批处理与事务比率,并且不向客户端返回任何事务信息(标头、描述符)。

“自动提交事务”模式足以处理上述示例中的事务 (1) 和 (3)。但是,该示例中的事务 (2) 需要多个批处理,因此需要手动管理事务。

手动管理事务

若要手动管理事务提交和回滚,SOAP 客户端必须在启动 SOAP 会话之前设置 sqloptions:environmentChangeNotification 选项,并在该标头中将其 transactionBoundary 属性设置为 true,如下列 SOAP 请求消息示例所示:

<SOAP-ENV:Envelope  xmlns:SOAP-ENV="https://schemas.xmlsoap.org/soap/envelope/"
              xmlns:sql="https://schemas.microsoft.com/sqlserver/2004/SOAP"
              xmlns:xsi="http://www.w3.org/2004/XMLSchema-instance"
              xmlns:sqlparam="https://schemas.microsoft.com/sqlserver/2004/sqltypes/SqlParameter"
              xmlns:sqlsoaptypes="https://schemas.microsoft.com/sqlserver/2004/sqltypes"
              xmlns:sqloptions="https://schemas.microsoft.com/sqlserver/2004/SOAP/Options">
  <SOAP-ENV:Header>
    <sqloptions:environmentChangeNotifications transactionBoundary="true" />
    <sqloptions:sqlSession initiate="true" timeout="60"/>
  </SOAP-ENV:Header>
  <SOAP-ENV:Body>
    <sql:sqlbatch>
      <sql:BatchCommands>
        USE master
        BEGIN TRANSACTION
        CREATE TABLE session_table (col1 int);
      </sql:BatchCommands>
    </sql:sqlbatch>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

此示例将通知服务器为当前会话禁用“自动提交事务”模式。然后服务器将向在其中标识会话 (jGqn3/X73EGHjFxZ12zovw==) 的下列示例发送类似的 SOAP 响应,并返回 SqlTransaction 值,用来确认服务器上的 BEGIN TRANSACTION 事件和客户端的事务描述符 (AQAAADMAAAA=),以便在同一事务的后续 SOAP 请求中使用。

<SOAP-ENV:Envelope xml:space="preserve"
                   xmlns:xsd="http://www.w3.org/2001/XMLSchema"
                   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
                   xmlns:SOAP-ENV="https://schemas.xmlsoap.org/soap/envelope/"
                   xmlns:sql="https://schemas.microsoft.com/sqlserver/2004/SOAP"
                   xmlns:sqlsoaptypes="https://schemas.microsoft.com/sqlserver/2004/SOAP/types"
                   xmlns:sqlrowcount="https://schemas.microsoft.com/sqlserver/2004/SOAP/types/SqlRowCount"                    xmlns:sqlmessage="https://schemas.microsoft.com/sqlserver/2004/SOAP/types/SqlMessage"                    xmlns:sqlresultstream="https://schemas.microsoft.com/sqlserver/2004/SOAP/types/SqlResultStream"                    xmlns:sqltransaction="https://schemas.microsoft.com/sqlserver/2004/SOAP/types/SqlTransaction"                    xmlns:sqltypes="https://schemas.microsoft.com/sqlserver/2004/sqltypes">
  <SOAP-ENV:Header xmlns:sqloptions="https://schemas.microsoft.com/sqlserver/2004/SOAP/Options">
    <sqloptions:sqlSession sessionId="jGqn3/X73EGHjFxZ12zovw==" timeout="1200">    </sqloptions:sqlSession>
  </SOAP-ENV:Header>
  <SOAP-ENV:Body>
    <sql:sqlbatchResponse>
       <sql:sqlbatchResult>
          <sqlresultstream:SqlTransaction xsi:type="sqltransaction:SqlTransaction">
             <sqltransaction:Descriptor>AQAAADMAAAA=</sqltransaction:Descriptor>
             <sqltransaction:Type>Begin</sqltransaction:Type>
          </sqlresultstream:SqlTransaction>
       </sql:sqlbatchResult>
    </sql:sqlbatchResponse>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

客户端使用服务器在上一个响应中返回的相同会话 ID 和事务描述符就可以在后续 SOAP 请求中手动联接事务。下面的示例说明了这一点。

<SOAP-ENV:Envelope  xmlns:SOAP-ENV="https://schemas.xmlsoap.org/soap/envelope/"
                    xmlns:sql="https://schemas.microsoft.com/sqlserver/2004/SOAP"
                    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                    xmlns:sqlparam="https://schemas.microsoft.com/sqlserver/2004/sqltypes/SqlParameter"
                    xmlns:sqlsoaptypes="https://schemas.microsoft.com/sqlserver/2004/sqltypes"
                    xmlns:sqloptions="https://schemas.microsoft.com/sqlserver/2004/SOAP/Options">
  <SOAP-ENV:Header>
    <sqloptions:sqlSession sessionId="jGqn3/X73EGHjFxZ12zovw==" transactionDescriptor="AQAAADMAAAA="/>
  </SOAP-ENV:Header>
  <SOAP-ENV:Body>
    <sql:sqlbatch>
      <sql:BatchCommands>
        INSERT INTO session_table values (2005)
        COMMIT TRANSACTION
      </sql:BatchCommands>
    </sql:sqlbatch>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

只要执行批处理的 SOAP 会话与开始事务的 SOAP 会话相同,SOAP 请求就可以显式联接该事务。否则,如果下列任何一个条件 True 时,SOAP 都将失败:

  • 指定了不同的 SOAP 会话 ID。

  • 未指定 SOAP 会话 ID。

  • 事务描述符对于当前 SOAP 会话无效。

sqlSession 标头的 transactionDescriptor 属性中一次只能使用一个事务。若要在同一个会话中创建多个独立的事务,可以通过使用 sqlSession 标头而不指定 transactionDescriptor 属性,在该会话中进行登记。请注意,此方法假定客户端应用程序跟踪不同的 transactionDescriptor 值。当多个独立的事务在相同的会话中都处于活动状态时,联接事务的操作是相同的,只需在 SOAP 请求的 sqlSession 标头中指定 transactionDescriptor 属性。

注意注意

若要确定活动嵌套事务的级别,可以读取并使用 Transact-SQL@@TRANCOUNT 函数的值。

sqlTransaction 的 XSD 架构

下面是在 SOAP 消息中使用的 sqlTransaction 标头的 XSD 架构:

<xsd:schema
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    attributeFormDefault="qualified"
    elementFormDefault="qualified"
    targetNamespace="https://schemas.microsoft.com/sqlserver/2004/SOAP/types/SqlTransaction">
<xsd:annotation><xsd:documentation xml:lang="en">&#xd;&#xa;(c) Copyright 2004, Microsoft Corporation&#xd;&#xa;&#xd;&#xa;The following schema for Microsoft SQL Server is presented in XML format and is for informational purposes only. Microsoft Corporation ("Microsoft") may have trademarks, copyrights, or other intellectual property rights covering subject matter in the schema.&#xd;&#xa;&#xd;&#xa;Microsoft does not make any representation or warranty regarding the schema or any product or item developed based on the schema. The schema is provided to you on an AS IS basis.  Microsoft disclaims all express, implied and statutory warranties, including but not limited to the implied warranties of merchantability, fitness for a particular purpose, and freedom from infringement. Without limiting the generality of the foregoing, Microsoft does not make any warranty of any kind that any item developed based on the schema, or any portion of the schema, will not infringe any copyright, patent, trade secret, or other intellectual property right of any person or entity in any country. It is your responsibility to seek licenses for such intellectual property rights where appropriate.&#xd;&#xa;&#xd;&#xa;MICROSOFT SHALL NOT BE LIABLE FOR ANY DAMAGES OF ANY KIND ARISING OUT OF OR IN CONNECTION WITH THE USE OF THE SCHEMA, INCLUDING WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, CONSEQUENTIAL (INCLUDING ANY LOST PROFITS), PUNITIVE OR SPECIAL DAMAGES, WHETHER OR NOT MICROSOFT HAS BEEN ADVISED OF SUCH DAMAGES.&#xd;&#xa;</xsd:documentation></xsd:annotation>
  <xsd:complexType name="SqlTransaction">
    <xsd:sequence minOccurs="1" maxOccurs="1">
      <xsd:element name="Descriptor" type="xsd:base64Binary" />
      <xsd:element name="Type">
         <xsd:simpleType>
            <xsd:restriction base="xsd:string">
              <xsd:enumeration value="Begin"/>
              <xsd:enumeration value="Commit"/>
              <xsd:enumeration value="Rollback"/>
              <xsd:enumeration value="EnlistDTC"/>
              <xsd:enumeration value="Defect"/>
            </xsd:restriction>
         </xsd:simpleType>
      </xsd:element>
    </xsd:sequence>
  </xsd:complexType>
</xsd:schema>

SQL 事务的 XSI 类型是 xsi:type="typesNs:SqlTransaction",其中 typesNs 已绑定到 https://schemas.microsoft.com/sqlserver/2004/SOAP/types/SqlTransaction 命名空间。