在 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
在 tempdb 数据库中创建此表:
USE tempdb CREATE TABLE Customer ( CustomerID varchar(5), ContactName varchar(20), LastUpdated timestamp)
添加此示例记录:
INSERT INTO Customer (CustomerID, ContactName) VALUES ('C1', 'Andrew Fuller')
复制以下 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>
将以下 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>
创建并使用 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>