在 Updategram 中处理数据库并发问题 (SQLXML 4.0)

与其他数据库更新机制一样,updategram 必须处理多用户环境下对数据的并发更新。Updategram 使用乐观并发控制,该模式将选择字段数据与快照进行比较,以确保要更新的数据自从在数据库中读取后,其他用户应用程序未更改过该数据。Updategram 在 updategram 的 <before> 块中包含这些快照值。在更新数据库前,updategram 将在 <before> 块中指定的值与当前数据库中的值进行比较,以确保更新有效。

乐观并发控制在 updategram 中提供三种保护级别:低(无)、中间和高。通过相应指定 updategram,可以确定需要的保护级别。

最低保护级别

此级别为盲目更新,它不参照自上次读取数据库后已进行的其他更新来处理更新。在这种情况下,仅在 <before> 块中指定主键列来标识记录,并在 <after> 块中指定更新后的信息。

例如,无论以前的电话号码是什么,以下 updategram 中的新联系人电话号码都是正确的。请注意 <before> 块如何仅指定主键列 (BusinessEntityID)。

<ROOT xmlns:updg="urn:schemas-microsoft-com:xml-updategram">
<updg:sync >
<updg:before>
   <Person.Person BusinessEntityID="1" />
</updg:before>
<updg:after>
   <Person.Person BusinessEntityID="1" Phone="111-111-1111" />
</updg:after>
</updg:sync>
</ROOT>

中间保护级别

在此保护级别中,updategram 将要更新的数据的当前值与数据库列中的值进行比较,以确保自您的事务读取记录后,这(个)些值未被任何其他事务更改过。

通过在 <before> 块中指定主键列和要更新的列,可以实现此保护级别。

例如,此 updategram 为 BusinessEntityID 是 1 的联系人更新 Person.Person 表的 Phone 列中的值。<before> 块指定 Phone 属性,以确保在应用更新的值之前此属性值与数据库中相应列的值匹配。

<ROOT xmlns:updg="urn:schemas-microsoft-com:xml-updategram">
<updg:sync >
<updg:before>
   <Person.Person BusinessEntityID="1" Phone="398-555-0132" />
</updg:before>
<updg:after>
   <Person.Person BusinessEntityID="1" Phone="111-111-1111" />
</updg:after>
</updg:sync>
</ROOT>

高保护级别

高保护级别确保自您的应用程序上次读取该记录后该记录没有变化(即自您的应用程序读取记录后,该记录未被任何其他事务更改过)。

可以通过两种方法实现针对并发更新的此类高保护级别:

  • 在 <before> 块中指定表的其他列。

    如果在 <before> 块中指定其他列,updategram 将为这些列指定的值与应用更新前数据库中的相应值进行比较。如果自您的事务读取记录后有记录列被更改过,updategram 将不执行更新。

    例如,以下 updategram 更新轮班时间,但是在 <before> 块中指定了其他列 (StartTime,EndTime),因此请求针对并发更新的更高保护级别。

    <ROOT xmlns:updg="urn:schemas-microsoft-com:xml-updategram">
    <updg:sync >
    <updg:before>
       <HumanResources.Shift ShiftID="1" 
                 Name="Day" 
                 StartTime="1900-01-01 07:00:00.000" 
                 EndTime="1900-01-01 15:00:00.000" />
    </updg:before>
    <updg:after>
       <HumanResources.Shift Name="Morning" />
    </updg:after>
    </updg:sync>
    </ROOT>
    

    此示例通过在 <before> 块中指定记录的所有列值,指定最高保护级别。

  • 在 <before> 块中指定时间戳列(如果可用)。

    如果不想在 <before> 块中指定所有记录列,可以在 <before> 块中只指定时间戳列(如果表包含此列)和主键列。在每次更新记录后,数据库将时间戳列更新为唯一值。在这种情况下,updategram 将时间戳的值与数据库中的相应值进行比较。在数据库中存储的时间戳值为二进制值。因此,必须在架构中将时间戳列指定为 dt:type="bin.hex"、dt:type="bin.base64" 或 sql:datatype="timestamp"。(可以指定 xml 数据类型或 Microsoft SQL Server 数据类型。)

测试 updategram

  1. tempdb 数据库中创建此表:

    USE tempdb
    CREATE TABLE Customer (
                 CustomerID  varchar(5),
                 ContactName varchar(20),
                 LastUpdated timestamp)
    
  2. 添加此示例记录:

    INSERT INTO Customer (CustomerID, ContactName) VALUES 
                         ('C1', 'Andrew Fuller')
    
  3. 复制以下 XSD 架构并将其粘贴到记事本中。将其另存为 ConcurrencySampleSchema.xml:

    <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
                xmlns:sql="urn:schemas-microsoft-com:mapping-schema">
      <xsd:element name="Customer" sql:relation="Customer" >
       <xsd:complexType>
            <xsd:attribute name="CustomerID"  
                           sql:field="CustomerID" 
                           type="xsd:string" /> 
    
            <xsd:attribute name="ContactName"  
                           sql:field="ContactName" 
                           type="xsd:string" />
    
            <xsd:attribute name="LastUpdated" 
                           sql:field="LastUpdated" 
                           type="xsd:hexBinary" 
                 sql:datatype="timestamp" />
    
        </xsd:complexType>
      </xsd:element>
    </xsd:schema>
    
  4. 将以下 updategram 代码复制到记事本中,然后在保存上一步中创建的架构的相同目录中将其保存为 ConcurrencySampleTemplate.xml。(请注意下面 LastUpdated 的时间戳值将不同于示例 Customer 表中的值,因此从表中复制 LastUpdated 的实际值并将其粘贴到 updategram。)

    <ROOT xmlns:updg="urn:schemas-microsoft-com:xml-updategram">
    <updg:sync mapping-schema="SampleSchema.xml" >
    <updg:before>
       <Customer CustomerID="C1" 
                 LastUpdated = "0x00000000000007D1" />
    </updg:before>
    <updg:after>
       <Customer ContactName="Robert King" />
    </updg:after>
    </updg:sync>
    </ROOT>
    
  5. 创建并使用 SQLXML 4.0 测试脚本 (Sqlxml4test.vbs) 执行该模板。

    有关详细信息,请参阅 使用 ADO 执行 SQLXML 4.0 查询

以下是等效的 XDR 架构:

<?xml version="1.0" ?>
<Schema xmlns="urn:schemas-microsoft-com:xml-data"
        xmlns:dt="urn:schemas-microsoft-com:datatypes"
        xmlns:sql="urn:schemas-microsoft-com:xml-sql">
<ElementType name="Customer" sql:relation="Customer" >
    <AttributeType name="CustomerID" />
    <AttributeType name="ContactName" />
    <AttributeType name="LastUpdated"  dt:type="bin.hex" 
                                       sql:datatype="timestamp" />
    <attribute type="CustomerID" />
    <attribute type="ContactName" />
    <attribute type="LastUpdated" />
</ElementType>
</Schema>