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 » 使用 Java 语言编写同步脚本

 

Java 同步示例

Java 同步逻辑与 MobiLink 及公用 Java 类配合工作,使您能够灵活地使用 MobiLink 服务器部署应用程序。下节将以简单的示例介绍这个广泛适用的功能。

本节介绍了 Java 同步逻辑的一个工作示例。在试图使用此类或编写您自己的类之前,请使用如下项目清单来确保在开始编译类之前做好一切准备工作。

  • 例如,使用伪代码等方法计划所需的功能。

  • 创建数据库表和列的结构图。

  • 确保已经在 MobiLink 系统表中指定了 Java 同步方法的语言类型和位置,从而针对 Java 同步配置好统一数据库。

    请参见设置 Java 同步逻辑

  • 创建将在 Java 类运行过程中调用的 Java 类相关列表。

  • 将您的 Java 类存储在 MobiLink 同步服务器类路径中的某个位置。

计划

此示例的 Java 同步逻辑指向为此示例的运行提供所需功能的相关 Java 文件和类。它将显示如何创建 CustEmpScripts 类。以及如何为连接设置同步上下文。最后,此示例还提供了实现如下功能的 Java 方法:

  • 验证 MobiLink 用户

  • 使用游标为每个数据库表执行下载和上载操作。

模式

要进行同步的表是 emp 和 cust。emp 表有三个列,分别为 emp_id、emp_name 和 manager。cust 表有三个列,分别为 cust_id、cust_name 和 emp_id。每个表中的所有列都进行同步。从统一数据库到远程数据库的映射保证在两个数据库中的表名和列名相同。另外在统一数据库中还添加了一个审计表。

Java 类文件

本示例中所使用的文件包含在 Samples\MobiLink\JavaAuthentication 目录中。

设置

以下代码将设置 Java 同步逻辑。其中 import 语句用于告知 Java 虚拟机所需文件的位置。public class 语句用于声明类。

// Use a package when you create your own script.
import ianywhere.ml.script.InOutInteger;
import ianywhere.ml.script.DBConnectionContext;
import ianywhere.ml.script.ServerContext;
import java.sql.*;

public class CustEmpScripts {
    // Context for this synchronization connection.
    DBConnectionContext _conn_context;

    // Same connection MobiLink uses for sync.
    // Do not commit or close this.
    Connection _sync_connection;
    Connection _audit_connection; 

    //Get a user id given the user name. On audit connection.
    PreparedStatement _get_user_id_pstmt;

    // Add record of user logins added. On audit connection.
    PreparedStatement _insert_login_pstmt;

    // Prepared statement to add a record to the audit table.
    // On audit connection.
    PreparedStatement _insert_audit_pstmt;
    
    // ...
}

CustEmpScripts 构造函数为 authenticateUser 方法设置所有预备语句。同时也设置成员数据。

public CustEmpScripts(DBConnectionContext cc) throws SQLException {
    try {
        _conn_context = cc;
        _sync_connection = _conn_context.getConnection();

        ServerContext serv_context =
        _conn_context.getServerContext();
        _audit_connection = serv_context.makeConnection();

        // Get the prepared statements ready.
        _get_user_id_pstmt =
            _audit_connection.prepareStatement(
                "select user_id from ml_user where name = ?"
            );

        _insert_login_pstmt =
            _audit_connection.prepareStatement(
                "INSERT INTO login_added(ml_user, add_time) "
                    + "VALUES (?, { fn CONVERT({ fn NOW() }, SQL_VARCHAR) })"
            );

        _insert_audit_pstmt =
            _audit_connection.prepareStatement(
                "INSERT INTO login_audit(ml_user_id, audit_time, audit_action) "
                    + "VALUES (?, { fn CONVERT({ fn NOW() }, SQL_VARCHAR) }, ?)"
            );
    }
    catch(SQLException e) {
        freeJDBCResources();
        throw e;
    }
    catch(Error e) {
        freeJDBCResources();
        throw e;
    }
}

如果没有调用 end_connection,finalize 方法将清理 JDBC 资源。该方法会调用 freeJDBCResources 方法,用以释放分配的内存并关闭审计连接。

protected void finalize() throws SQLException, Throwable {
    super.finalize();
    freeJDBCResources();
}

private void freeJDBCResources() throws SQLException {
    if (_get_user_id_pstmt != null) {
        _get_user_id_pstmt.close();
    }
    if (_insert_login_pstmt != null) {
        _insert_login_pstmt.close();
    }
    if (_insert_audit_pstmt != null) {
        _insert_audit_pstmt.close();
    }
    if (_audit_connection != null) {
        _audit_connection.close();
    }
    _conn_context       = null;
    _sync_connection    = null;
    _audit_connection   = null;
    _get_user_id_pstmt  = null;
    _insert_login_pstmt = null;
    _insert_audit_pstmt = null;
}

endConnection 方法会在资源不再需要时将其清理掉。

public void endConnection() throws SQLException {
    freeJDBCResources();
}

下面的 authenticateUser 方法将批准所有用户登录,并将用户信息记录到数据库表中。如果用户不在 ml_user 表中,则他们将被记录到 login_added 中。如果用户 ID 在 ml_user 中,则他们将被记录到 login_audit 中。在真实的系统中不会忽略 user_password,但为简单起见,本示例将批准所有用户。如果任何数据库操作因异常而失败,endConnection 方法都将抛出 SQLException。

public void authenticateUser( 
    InOutInteger authentication_status,
    String user_name) throws SQLException 
{

    boolean new_user;
    int user_id;

    // Get ml_user id.
    _get_user_id_pstmt.setString(1, user_name);

    ResultSet user_id_rs =
    _get_user_id_pstmt.executeQuery();
    new_user = !user_id_rs.next();
    if (!new_user) {
        user_id = user_id_rs.getInt(1);
    }
    else {
        user_id = 0;
    }
 
    user_id_rs.close();
    user_id_rs = null;

    // In this tutorial always allow the login.
    authentication_status.setValue(1000);
  
    if (new_user) {
        _insert_login_pstmt.setString(1, user_name);
        _insert_login_pstmt.executeUpdate();
        java.lang.System.out.println("user: " + user_name + " added. ");
    }
    else {
        _insert_audit_pstmt.setInt(1, user_id);
        _insert_audit_pstmt.setString(2, "LOGIN ALLOWED");
        _insert_audit_pstmt.executeUpdate();
    }
    _audit_connection.commit();
    return;
}

以下方法使用 SQL 代码充当数据库表上的游标。既然它们是游标脚本,因此必须返回一个 SQL 字符串。

public static String empUploadInsertStmt() {
    return("INSERT INTO emp(emp_id, emp_name) VALUES(?, ?)");
}

public static String empUploadDeleteStmt() {
    return("DELETE FROM emp WHERE emp_id = ?");
}

public static String empUploadUpdateStmt() {
    return("UPDATE emp SET emp_name = ? WHERE emp_id = ?");
} 

public static String empDownloadCursor() {
    return("SELECT emp_id, emp_name FROM emp");
}

public static String custUploadInsertStmt() {
    return("INSERT INTO cust(cust_id, emp_id, cust_name) VALUES (?, ?, ?)");
}

public static String custUploadDeleteStmt() {
    return("DELETE FROM cust WHERE cust_id = ?");
} 

public static String custUploadUpdateStmt() {
    return("UPDATE cust SET emp_id = ?, cust_name = ? WHERE cust_id = ?");
}

public static String custDownloadCursor() {
    return("SELECT cust_id, emp_id, cust_name FROM cust");
}

使用以下命令编译代码:

javac -cp %sqlany11%\java\mlscript.jar CustEmpScripts.java

以 CustEmpScripts.class 在类路径中的位置运行 MobiLink 服务器。下面是命令行的一部分:

mlsrv11 ... -sl java (-cp <class_location>)