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

SAP Sybase SQL Anywhere 16.0 (中文) » MobiLink - 客户端管理 » 用于 MobiLink 的 SQL Anywhere 客户端 » 脚本式上载 » 教程:使用脚本式上载

 

第 4 课:处理更新

在本课中,您将创建表、触发器和用于处理更新的存储过程。

前提条件

本课假定您拥有在本教程(教程:使用脚本式上载)开头的“特权”部分中列出的角色和特权。

本课假定您已完成前面的所有课程。 请参见第 1 课:创建统一数据库

上下文和注释

若要处理上载,必须确保根据构建上载时的开始进度使用正确的前映像。

 任务
  1. 使用连接到远程数据库的 Interactive SQL 实例,创建一个表,该表用于维护已更新行的前映像。生成脚本式上载时将使用前映像。

    CREATE TABLE employee_preimages (
       id           unsigned integer NOT NULL,
       name         varchar( 256),
       salary       numeric( 9, 2 ),
       img_time     timestamp default CURRENT TIMESTAMP,
       primary key( id, img_time )
    );
  2. 接下来,创建一个触发器,此触发器在更新每一行时存储该行的前映像。与插入触发器一样,下载时不触发此触发器。

    CREATE TRIGGER emp_upd AFTER UPDATE OF name,salary ON employee
       REFERENCING OLD AS oldrow
       FOR EACH ROW
    BEGIN
       INSERT INTO employee_preimages ON EXISTING SKIP VALUES(
          oldrow.id, oldrow.name, oldrow.salary, CURRENT TIMESTAMP );
    END;

    每次更新行时,此触发器均存储前映像行(除非两次更新时间太近,致使它们获得相同的时间戳)。乍看起来这种方法浪费了资源。只有在表中没有行的前映像时才存储前映像,在上载前映像后依靠 sp_hook_dbmlsync_upload_end 挂接将其删除,这种方法更具吸引力。

    但是,sp_hook_dbmlsync_upload_end 挂接在这种方法中并不可靠。如果在发送上载后确认上载前的这段时间内由于发生硬件或软件故障停止了 dbmlsync,则不会调用此挂接,从而导致不会从前映像表中删除行,即使这些行已成功上载。另外,如果发生通信故障,dbmlsync 也不会从服务器收到上载确认。在这种情况下,传送到挂接的上载状态为 'unknown'。如果发生这种情况,则挂接将无法判断前映像表是应该清除还是应该保留原样。通过存储多个前映像,将始终能够根据构建上载时的开始进度选择正确的前映像。

  3. 接下来,创建一个用于处理更新的上载过程。



    CREATE PROCEDURE employee_update()
    RESULT(
           preimage_id  unsigned integer,
           preimage_name varchar( 256),
           preimage_salary numeric( 9,2 ),
           postimage_id  unsigned integer,
           postimage_name varchar( 256),
           postimage_salary numeric( 9,2 )
          )
    BEGIN
        DECLARE start_time timestamp;
    
        SELECT value
        INTO start_time
        FROM #hook_dict
        WHERE name = 'start progress as timestamp';
    
        // Upload as an update all rows that have been updated since 
        // start_time that were not newly inserted or deleted.
        SELECT ep.id, ep.name, ep.salary, e.id, e.name, e.salary
        FROM employee e JOIN employee_preimages ep 
            ON ( e.id = ep.id )
        // Do not select rows inserted since the start time. These should be
        // uploaded as inserts.
        WHERE insert_time <= start_time 
          // Do not upload deleted rows.
          AND NOT EXISTS( SELECT id FROM employee_delete ed  WHERE ed.id = e.id )
          // Select the earliest pre-image after the start time.
          AND ep.img_time = ( SELECT MIN( img_time )
                FROM employee_preimages
                WHERE id = ep.id
                AND img_time > start_time );
    END;

    此存储过程返回一个所包含列数为其它脚本包含列数两倍的结果集:该结果集包含前映像(上次从 MobiLink 服务器接收或成功上载到 MobiLink 服务器时行中的值)和后映像(要输入到统一数据库中的值)。

    前映像是 employee_preimages 中在 start_progress 后记录的最早的一组值。此示例不能正确处理删除后再次插入的现有行。在更完整的解决方案中,这些将作为更新上载。

结果

创建了一个用来存储前映像的表、一个用于存储各个已更新行的前映像的触发器,以及一个用来处理更新的存储过程。

下一个

前进至第 5 课:处理删除