Click here to view and discuss this page in DocCommentXchange. In the future, you will be sent there automatically.

SQL Anywhere 11.0.1 (中文) » SQL Remote » SQL Remote 复制设计 » SQL Remote 复制设计和设置 » 使用无交集数据分区

 

使用 BEFORE UDPATE 触发器

在下面的示例中,有三个表存储着销售代表和客户之间的交互信息:Customers、Contacts 和 SalesReps。每个销售代表都向若干个客户销售产品。某些客户只有一个联系人,而另一些客户则有多个联系人。

Contacts 表具有一个指向 Customers 表的外键。Customer 表具有一个指向 SalesRep 表的外键。

有关这些表的详细说明,请参见Contacts、Customers 和 SalesReps 表的说明

一个销售代表预订了一个发布,该发布提供了一份 SalesRep 表、一份含有指派给这些销售代表的客户的详细信息的 Customers 表以及一份含有对应于他们的客户的联系人详细信息的 Contacts 表。例如,每个销售代表都预订了以下的发布:

CREATE PUBLICATION SalesRepData (
   TABLE SalesReps
   TABLE Customers
      SUBSCRIBE BY rep_key
   TABLE Contacts
      SUBSCRIBE BY (SELECT rep_key
         FROM Customers
         WHERE Contacts.cust_key = Customers.cust_key )
);

有关此发布的详细说明,请参见使用无交集数据分区

保持参照完整性

这种在预订者之间重新指派行的做法有时称为地域调整,因为它是销售人员自动应用程序的常见功能,在这种功能中客户被定期重新指派给销售代表。

在统一数据库中,将某客户重新指派给新的销售代表时,就会相应更新 Customers 表中的 rep_key 值。

以下语句会将客户 cust1 重新指派给另一个销售代表 rep2。

UPDATE Customers
SET rep_key = 'rep2'
WHERE cust_key = 'cust1';

此更新以下面的方式被复制:

  • 作为一个 DELETE 语句复制到以前的销售代表的远程数据库的 Customers 表中。

  • 作为一个 INSERT 语句复制到新销售代表的远程数据库的 Customers 表中。

Contacts 表发生改变。在统一数据库的事务日志中没有关于 Contacts 表的条目。这样,远程数据库中的 SQL Remote 无法重新指派 Contacts 表的 cust_key 行。这将导致产生以下参照完整性问题:以前的销售代表的远程数据库中的 Contacts 表包含一个不再有客户的 cust_key 值。

解决方法是使用 BEFORE UPDATE 触发器。BEFORE UPDATE 触发器不会对数据库表进行任何更改,但会在统一数据库的事务日志中创建一个条目。

触发 BEFORE UPDATE 触发器必须满足以下条件:

  • 在运行 UPDATE 语句前触发。以便计算行的 BEFORE 值并将其添加到事务日志。

  • 针对每行,而不是针对每个语句。由触发器提供的信息必须是新的预订表达式。

例如,下面的语句将创建一个 BEFORE UPDATE 触发器。

CREATE TRIGGER "UpdateCustomer" BEFORE UPDATE OF "rep_key"
// only fire the trigger when we modify rep_key, not any other column
ORDER 1 ON "Cons"."Customers"
/* REFERENCING OLD AS old_name NEW AS new_name */
REFERENCING NEW AS NewRow
   OLD AS OldRow
FOR EACH ROW 
BEGIN
// determine the new subscription expression
   // for the Customers table
	 UPDATE Contacts
   PUBLICATION SalesRepData
   OLD SUBSCRIBE BY ( OldRow.rep_key )
   NEW SUBSCRIBE BY ( NewRow.rep_key )
   WHERE cust_key = NewRow.cust_key;
END
;

SQL Remote 使用事务日志中的信息来确定哪些预订者接收哪些行。

执行了该语句后,统一数据库事务日志中将包含两个条目:

  • 由 BEFORE UPDATE 触发器生成的用于 Contacts 表的 INSERT 和 DELETE 语句。

    --BEGIN TRIGGER-1029-0000461705
    --BEGIN TRANSACTION-1029-0000461708
    BEGIN TRANSACTION
    go
    --UPDATE PUBLICATION-1029-0000461711 Cons.Contacts
    --PUBLICATION-1029-0000461711-0002-NEW_SUBSCRIBE_BY-rep2
    --PUBLICATION-1029-0000461711-0002-OLD_SUBSCRIBE_BY-rep1
    --NEW-1029-0000461711
    --INSERT INTO Cons.Contacts(contact_key,name,cust_key)
    --VALUES ('5','Joe','cust1')
    go
    --OLD-1029-0000461711
    --DELETE FROM Cons.Contacts
    -- WHERE contact_key='5'
    go
    --END TRIGGER-1029-0000461743
    
  • 执行的原始 UPDATE 语句以及分别获得行或丢失行的这些用户的 INSERT 和 DELETE 语句。

    --PUBLICATION-1029-0000461746-0002-NEW_SUBSCRIBE_BY-rep2
    --PUBLICATION-1029-0000461746-0002-OLD_SUBSCRIBE_BY-rep1
    --NEW-1029-0000461746
    --INSERT INTO Cons.Customers(cust_key,name,rep_key)
    --VALUES ('cust1','company1','rep2')
    go
    --OLD-1029-0000461746
    --DELETE FROM Cons.Customers
    -- WHERE cust_key='cust1'
    go
    --UPDATE-1029-0000461746
    UPDATE Cons.Customers
       SET rep_key='rep2'
    VERIFY (rep_key)
    VALUES ('1')
     WHERE cust_key='cust1'
    go
    --COMMIT-1029-0000461785
    COMMIT WORK

SQL Remote 会对事务日志进行扫描以查找 BEFORE 和 AFTER 标记。根据此信息,它可以确定哪些远程用户得到了 INSERT、UPDATE 或 DELETE 语句。

  • 当用户在 BEFORE 列表中而不在 AFTER 列表中时,会将 DELETE 语句发送到 Contacts 表中。

  • 当用户在 AFTER 列表中而不在 BEFORE 列表中时,会将 INSERT 语句发送到 Contacts 表中。

  • 如果用户既在 BEFORE 列表中又在 AFTER 列表中,则不会对 Contacts 表执行任何操作,但是会发送 Customers 表中的 UPDATE 语句。

如果 BEFORE 和 AFTER 列表相同,则远程用户已具有该行,并将发送 UPDATE 语句。

有关触发器的说明

在以下示例中,必须使用 BEFORE UPDATE 触发器。在其它上下文中,BEFORE DELETE 和 BEFORE INSERT 都是必需的。

UPDATE table-name
PUBLICATION pub-name
   SUBSCRIBE BY sub-expression
WHERE search-condition;

在本示例中,使用 BEFORE 触发器。

UPDATE table-name
PUBLICATION publication-name
   OLD SUBSCRIBE BY old-subscription-expression
   NEW SUBSCRIBE BY new-subscription-expression
WHERE search-condition;

UPDATE 语句列出了受影响的发布和表。语句中的 WHERE 子句说明了受影响的行。此 UPDATE 语句没有更改表中的数据,它只在事务日志中生成条目。

在本示例中,预订表达式返回单个值。但也可以使用返回多个值的子查询。预订表达式的值必须是更新后的值。

在本示例中,该行的唯一预订者是新销售代表。有关具有现有预订者和新预订者的行的示例,请参见使用有交集分区