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

SQL Anywhere 11.0.1 (中文) » MobiLink - 服务器管理 » MobiLink 服务器 API » 直接行处理 » 处理直接上载

 

直接上载的冲突处理

在 MobiLink 客户端向 MobiLink 服务器发送一个更新后的行时,发送的数据中不仅包含更新后的值(后映像或新行),而且还将包含那些上次与 MobiLink 服务器同步时获得的旧行值的副本(前映像或旧行)。如果前映像行与中央数据源中的当前值不匹配,表示检测到了冲突。

基于 SQL 的冲突解决

对于基于 SQL 的上载,MobiLink 统一数据库是您的中央数据源,并且 MobiLink 为冲突的检测和解决提供了特殊事件。

请参见冲突处理

使用直接行处理解决冲突

对于直接上载,可以编程方式访问新旧行以便冲突的检测和解决。

UpdateResultSet(由 UploadedTableData.getUpdates 方法返回)扩展标准 Java 或 .NET 结果集以包括处理冲突的特殊方法。setNewRowValues 设置 UpdateResultSet 以从远程客户端返回新的更新后的值(缺省模式)。setOldRowValues 设置 UpdateResultSet 以返回旧行值。

使用直接行处理检测冲突

通过使用 UpdateResultSet 方法 .setOldRowValues,在远程某行的值被更改之前获取该行的值。将返回的行值与数据源中的现有行值进行比较。如果比较的行不相等,则存在冲突。

使用直接行处理解决冲突

一旦在上载期间检测到冲突,您可以使用自定义业务逻辑来解决冲突。冲突的解决通过 Java 或 .NET 代码进行处理。

示例

假定您在 XML 文档中跟踪库存并想要将其用作中央数据源。User1 使用您的远程数据库中名为 Remote1 的数据库。User2 使用名为 Remote2 的另一远程数据库。

您的 XML 文档、User1 和 User2 开始时的库存都为 10 件。User1 卖出 3 件并将 Remote1 的库存值更新为 7 件。User2 卖出 4 件并将 Remote2 的库存更新为 6 件。当 Remote1 同步时,中央数据库将被更新为 7 件。Remote2 同步时,由于库存值不再是 10 个项目,因此会检测到冲突。若要以编程方式解决这一冲突,需要三个行值:

  • 中央数据源中的当前值。

  • Remote2 上载的新行值。

  • Remote2 在上一次同步期间获取的旧行值。

在这种情况下,业务逻辑将使用以下公式来计算新的库存值,并解决冲突:

current data source - (old remote - new remote)
-> 7 - (10-6) = 3

以下 Java 和 .NET 过程演示了如何解决此直接上载冲突,以下表为例:

CREATE TABLE remoteOrders
(
    pk integer primary key not null,
    inventory integer not null
);
♦  处理直接冲突 (Java)
  1. 为 handle_UploadData 连接事件注册一个 Java 或 .NET 方法。

    请参见handle_UploadData 连接事件

    例如,以下存储过程调用在同步脚本版本 ver1 时,为 handle_UploadData 连接事件注册一个称为 HandleUpload 的 Java 方法。针对您的 MobiLink 统一数据库运行此存储过程。

    call ml_add_java_connection_script( 'ver1',
       'handle_UploadData',
       'OrderProcessor.HandleUpload' )

    有关为同步事件注册方法的详细信息,请参见:

  2. 获取上载中表的 UpdateResultSet。

    OrderProcessor.HandleUpload 方法获取 remoteOrders 表的 UpdateResultSet:

    // method for handle_UploadData event
     public void HandleUpload( UploadData u_data )
     {
     
        // Get UploadedTableData for the remoteOrders table.
          UploadedTableData u_table = u_data.getUploadedTableByName("remoteOrders");
       
        // Get an UpdateResultSet for the remoteOrders table.
        UpdateResultSet update_rs = u_table.getUpdates();
       
        // (Continued...)
  3. 针对每次更新,获取中央数据源中的当前值。

    在本例中,UpdateResultSet getInt 方法返回主键列(第一列)的整数值。您可以实现 getMyCentralData 方法,然后使用该方法从中央数据源获取数据。

    while( update_rs.next() )
    {
       // Get central data source values.
    
       // Get the primary key value.
       int pk_value = update_rs.getInt(1);
    
       // Get central data source values.
       int central_value = getMyCentralData(pk_value);
    
       // (Continued...)
  4. 针对每次更新,获取由 MobiLink 客户端上载的旧值和新值。

    该示例分别将 UpdateResultSet setOldRowValues 和 UpdateResultSet setNewRowValues 用于旧值和新值。

      // Set mode for old row values.
      update_rs.setOldRowValues();
    
      // Get the _old_ stored value on the remote.
      int old_value = update_rs.getInt(2);
    
      // Set mode for new row values.
      update_rs.setNewRowValues();
    
      // Get the _new_ updated value on the remote.
      int new_value = update_rs.getInt(2);
    
      // (Continued...)
  5. 针对每次更新,检查冲突。

    旧行值与中央数据源中的当前值不匹配时,将发生冲突。要解决冲突,通过使用业务逻辑来计算解决值。如果未发生冲突,将用新的远程值对中央数据源进行更新。您可以实现 setMyCentralData 方法,然后使用该方法来执行更新。

      // Check if there is a conflict.
    
      if(old_value == central_value)
      {
        // No conflict.
        setMyCentralData(pk_value, new_value);
       
      }
      else
      {
        // Handle the conflict.
        int inventory = old_value - new_value;
        int resolved_value = central_value - inventory;
      
        setMyCentralData(pk_value, resolved_value);
    
      }
    }
♦  处理直接冲突 (.NET)
  1. 为 handle_UploadData 连接事件注册一个方法。

    例如,以下存储过程调用在同步脚本版本 ver1 时,为 handle_UploadData 连接事件注册一个称为 HandleUpload 的 .NET 方法。针对您的 MobiLink 统一数据库运行此存储过程。

    call ml_add_dnet_connection_script( 'ver1',
       'handle_UploadData',
       'MyScripts.OrderProcessor.HandleUpload' )

    有关为同步事件注册方法的详细信息,请参见:

  2. 获取上载中表的 UpdateDataReader。

    MyScripts.OrderProcessor.HandleUpload 方法获取 remoteOrders 表的 UpdateResultSet:

    // method for handle_UploadData event
     public void HandleUpload( UploadData u_data )
     {
     
        // Get UploadedTableData for the remoteOrders table.
          UploadedTableData u_table = u_data.GetUploadedTableByName("remoteOrders");
       
        // Get an UpdateDataReader for the remoteOrders table.
        UpdateDataReader update_dr = u_table.GetUpdates();
       
        // (Continued...)
  3. 针对每次更新,获取中央数据源中的当前值。

    在本例中,UpdateDataReader GetInt32 方法返回主键列(第一列)的整数值。您可以实现 getMyCentralData 方法,然后使用该方法从中央数据源获取数据。

    while( update_dr.Read() )
    {
       // Get central data source values.
    
       // Get the primary key value.
       int pk_value = update_dr.GetInt32(0);
    
       // Get central data source values.
       int central_value = getMyCentralData(pk_value);
    
       // (Continued...)
  4. 针对每次更新,获取由 MobiLink 客户端上载的旧值和新值。

    该示例分别将 UpdateResultSet setOldRowValues 和 UpdateResultSet setNewRowValues 用于旧值和新值。

      // Set mode for old row values.
      update_dr.SetOldRowValues();
    
      // Get an _old_ value.
      int old_value = update_dr.GetInt32(1);
    
      // Set mode for new row values.
      update_dr.SetNewRowValues();
    
      // Get the _new_ updated value.
      int new_value = update_dr.GetInt32(1);
    
      // (Continued...)
  5. 针对每次更新,检查冲突。

    旧行值与中央数据源中的当前值不匹配时,将发生冲突。要解决冲突,通过使用业务逻辑来计算解决值。如果未发生冲突,将用新的远程值对中央数据源进行更新。您可以实现 setMyCentralData 方法,然后使用该方法来执行更新。

      // Check if there is a conflict.
    
      if(old_value == central_value)
      {
        // No conflict.
        setMyCentralData(pk_value, new_value);
       
      }
      else
      {
        // Handle the conflict.
        int inventory = old_value - new_value;
        int resolved_value = central_value - inventory;
      
        setMyCentralData(pk_value, resolved_value);
    
      }
    }