辅助功能*

H. Paul Robertson

H. Paul Robertson

Adobe
博客*

出版日期:
2008 年 2 月 28 日
用户级别:
中/高级
产品:
Adobe AIR

异步处理本地 SQL 数据库

我们特意将本文所讨论的范例应用程序设计得很简单。该应用程序在计算机的内存中创建一个数据库, 并在该数据库中创建一个表, 然后向数据库添加一些数据。单击 Load data (加载数据) 按钮, 然后检索数据, 并将其显示在屏幕上 (见图 1)。除了在单击按钮时加载数据以及在屏幕上显示这些数据之外, 不提供其它用户交互。特意这样做是为了使应用程序的重点完全放在数据库操作上。本范例应用程序演示 Adobe AIR 的以下功能:

  • 使用异步执行模式连接至本地 SQL 数据库
  • 异步创建和执行 SQL 语句:
    • 在数据库中创建表
    • 向数据库表中插入数据
    • 从数据库表中检索数据, 并在屏幕上显示这些数据

简单的本地数据库

图 1。通过本范例应用程序可以从数据库中加载数据。

注意: 本范例应用程序按原样提供, 用于教学目的。

要求

若要充分利用本篇文章, 您需要以下软件和文件:

Adobe AIR

Adobe AIR SDK

范例文件:

本范例应用程序包括以下文件:

  • SimpleDBExampleHTML.html: 应用程序主要源代码
  • AIRAliases.js: AIR JavaScript 别名文件
  • application.xml: AIR 应用程序描述符文件
  • AIR 图标文件范例

必备知识

应具备构建 HTML 应用程序的一般经验。有关使用此快速入门指南的详细信息, 请参阅用 HTML 构建快速入门范例应用程序

了解代码

本部分将不一一介绍文件中的全部 HTML 标记, 而仅介绍专门针对 AIR 的 JavaScript 代码。

连接至本地 SQL 数据库

应用程序加载完毕时调用 init() 方法, 正如 body 标签的 onload 事件处理函数中所定义。在此方法中创建 SQLConnection 实例名 conn。 (在方法外声明变量 conn, 以使该变量对应用程序中的所有代码都可用。) 此 SQLConnection 对象建立到数据库的连接, 并由其它对象用于对该特定数据库执行操作。创建 SQLConnection 实例后, 即针对该实例注册一些事件侦听器, 以便在打开数据库连接 (或 openAsync() 操作失败) 时调用这些侦听器, 并调用 openAsync() 方法, 以异步执行模式打开到数据库的连接。

conn = new air.SQLConnection();
conn.addEventListener(air.SQLEvent.OPEN, openSuccess);
conn.addEventListener(air.SQLErrorEvent.ERROR, openFailure);
conn.openAsync(null);

在本例中, 将 null 作为参数传递至 openAsync() 方法, 表示运行时将在计算机的内存中而非在磁盘位置中创建数据库。此外, 还可以 (使用 File 实例) 指定文件位置。然后, 运行时将打开该位置的数据库文件 (如果文件不存在, 则首先创建该文件)。执行该任务的代码如下所示:

var dbFile = air.File.applicationStorageDirectory.resolvePath("DBSample.db");
conn.openAsync(dbFile);

air.File.applicationStorageDirectory 指向 AIR 应用程序的存储目录, 该目录的定义对于每个 AIR 应用程序都是独一无二的。

假定 openAsync() 操作成功并且打开了数据库连接, 则调用 openSuccess() 方法。该方法只是执行解除事件侦听器注册关系的清理操作, 并调用 createTable() 方法, 在数据库中创建表。

在数据库中创建表

createTable() 方法使用 SQLStatement 实例, 针对在 init() 方法中打开的数据库执行一条 SQL 命令。这条具体的 SQL 命令在数据库中创建一个名为“employees”的表, 其中包括四列。以下将代码分解, 分别介绍各段代码的作用:

  1. 创建名为 createStmt 的 SQLStatement 实例:

    createStmt = new air.SQLStatement();
  2. 指定对通过 SQLConnection 实例 conn 连接的数据库执行语句:

    createStmt.sqlConnection = conn;
  3. 定义用于创建数据库表的 SQL 语句文本。将表命名为“employees”。该表包含四列: “empId”、“firstName”、“lastName”和“salary”。

    var sql = "";
    sql += "CREATE TABLE IF NOT EXISTS employees ( ";
    sql += "empId INTEGER PRIMARY KEY AUTOINCREMENT, ";
    sql += "firstName TEXT, ";
    sql += "lastName TEXT, ";
    sql += "salary NUMERIC CHECK (salary >= 0) DEFAULT 0";
    sql += ")";
    createStmt.text = sql;
  4. 注册事件侦听器, 用于指定语句执行完毕 (createResult) 或失败 (createError) 时调用的方法:

    createStmt.addEventListener(air.SQLEvent.RESULT, createResult);
    createStmt.addEventListener(air.SQLErrorEvent.ERROR, createError);
  5. 执行语句:

    createStmt.execute();

假定语句成功运行, 则创建“employees”表, 并调用 createResult() 方法。该方法删除已注册的侦听器, 并调用 addData() 方法以执行过程中的下一步: 向新创建的表中添加数据。

向数据库表中插入数据

createTable() 方法一样, addData() 方法创建 SQLStatement, 在本例中是为了向数据库的“employees”表中插入一行数据。应用程序使用两个不同的 SQLStatement 实例 (insertStmtinsertStmt2) 插入两行数据:

insertStmt = new air.SQLStatement();
insertStmt.sqlConnection = conn;
var sql = "";
sql += "INSERT INTO employees (firstName, lastName, salary) ";
sql += "VALUES ('Bob', 'Smith', 8000)";
insertStmt.text = sql;
    
insertStmt.addEventListener(air.SQLEvent.RESULT, insertResult);
insertStmt.addEventListener(air.SQLErrorEvent.ERROR, insertError);
    
insertStmt.execute();
    
insertStmt2 = new air.SQLStatement();
insertStmt2.sqlConnection = conn;
var sql2 = "";
sql2 += "INSERT INTO employees (firstName, lastName, salary) ";
sql2 += "VALUES ('John', 'Jones', 8200)";
insertStmt2.text = sql2;
    
insertStmt2.addEventListener(air.SQLEvent.RESULT, insertResult);
insertStmt2.addEventListener(air.SQLErrorEvent.ERROR, insertError);
    
insertStmt2.execute();

注意, 由于执行第二条语句不依赖于第一条语句的结果, 因此在调用第一个实例的 execute() 方法之后立即创建第二个 SQLStatement 实例, 并调用其 execute() 方法。 (而不是等待第一条 INSERT 语句的 result 事件后再执行第二条语句。) 运行时将这两条语句排队, 在第一条语句完成后立即执行第二条语句。

唯一的复杂因素是代码需要确定两条语句都已完成, 然后才开始从数据库中检索数据。为此, 在 (触发每个 SQLStatement 的 result 事件时调用的) insertResult() 方法中, 应用程序确定哪条语句执行完毕, 然后检查是否两条语句都已执行完毕。如果都已执行完毕, 则将状态栏文本 (statustext.innerText) 更新为“Ready to load data” (已准备好加载数据), 此时应用程序已准备好从数据库中检索数据以及在屏幕上显示这些数据:

private function insertResult(event)
{
    var stmt = event.target;
    
    stmt.removeEventListener(air.SQLEvent.RESULT, insertResult);
    stmt.removeEventListener(air.SQLErrorEvent.ERROR, insertError);
    
    if (stmt == insertStmt)
    {
        insert1Complete = true;
    }
    else
    {
        insert2Complete = true;
    } 	        
    
    if (insert1Complete && insert2Complete)
    {
        statustext.innerText = "Ready to load data";
    }
}

从数据库表中检索数据

就像创建表以及向表中插入数据一样, 从表中检索数据也是通过创建 SQLStatement 实例, 并将 SQL SELECT 语句作为 SQLStatement 实例的 text 属性。以下代码来自 getData() 方法, 这段代码创建并执行从“employees”表中检索所有行的 SELECT 语句:

selectStmt = new air.SQLStatement();
selectStmt.sqlConnection = conn;
var sql = "SELECT empId, firstName, lastName, salary FROM employees";
selectStmt.text = sql;
    
selectStmt.addEventListener(air.SQLEvent.RESULT, selectResult);
selectStmt.addEventListener(air.SQLErrorEvent.ERROR, selectError);
    
selectStmt.execute();

正如代码中所指, SELECT 语句执行完毕时将调用 selectResult() 方法。在 selectResult() 中, 通过调用 SQLStatement 实例的 getResult() 方法, 访问由 SELECT 语句检索的结果数据。调用 getResult() 将返回存储在变量 result 中的 SQLResult 实例;实际的各行结果包含在该变量的 data 属性的一个数组中。这些结果用于生成 HTML 表的各行, 具体方法是遍历 data 数组中的各行数据, 然后遍历每行中的各列, 为行和单元格生成 trtd 元素, 并将这些元素追加至一个名为 resultsGrid 的表 (已在 HTML 中定义):

function selectResult(event)
{
    // ... 清理 ...
    
    var result = selectStmt.getResult();
    
    var row;
    var cell;
    
    var tbl = document.getElementById("resultsGrid");
    tbl.innerHTML = "";
    
    var numRows = result.data.length;
    for (var i = 0; i < numRows; i++)
    {
        if (i == 0)
        {
            // 添加表格标题
            row = document.createElement("tr");
            
            for (col in result.data[i])
            {
                cell = document.createElement("th");
                cell.innerText = col;
                row.appendChild(cell);
            }
            
            tbl.appendChild(row);
        }
        
        // 遍历结果行对象中的各列
        row = document.createElement("tr");
        
        for (col in result.data[i])
        {
            cell = document.createElement("td");
            cell.innerText = result.data[i][col];
            row.appendChild(cell);
        }
        
        tbl.appendChild(row);
    }
}

关于作者

H. Paul Robertson 是 Adobe Systems 公司的平台开发人员文档团队的一名 ActionScript 开发人员/文档撰写人员。他曾作为一名 Web 应用程序开发人员与 Russell Chun 共同编写了《Macromedia Flash 8 Advanced: Visual QuickPro Guide》* (Peachpit 出版社, 2005 年)。Paul 是一名 Flash 认证开发人员, 拥有印地安那大学的教学系统技术专业硕士学位。在编写 Web 应用程序、撰写关于 Web 应用程序的稿件、讲授 Web 应用程序课程或更新博客*之余, Paul 喜欢收集各种厨房用具, 并乐于同他的三个孩子在乐高玩具、星球大战游戏等各种重大游艺项目上一争高下。