23.14.1.問題
我想讓應用程序在本地保存和接收數據。
23.14.2.解決辦法
在用戶硬盤上創建數據庫文件,執行SQL語句。
23.14.3.討論
Adobe AIR 運行時引入了SQL數據庫引擎,使我們可以為創建本地數據庫存儲信息。一個數據庫被保存為一個文件,且沒有限定存放于特定的目錄下,這樣可允許任何應用程序都可訪問數據庫中的數據。AIR的SQL引擎可創建關系型數據庫,用標準SQL語句存儲和接受復雜數據。
SQL 數據庫API 包含幾個類,提供創建和打開數據庫,生成語句,監聽操作事件,檢索有關數據庫的架構信息。使用flash.filesystem.File類用合法的擴展名創建數據庫文件。使用Flash.dataSQLConnection類的open和openAsync方法建立一個數據庫連接。如果你沒有傳遞File引用給open和openAsync方法,則會在內存中創建一個數據庫并允許執行SQL語句。SQL語句可被同步和異步執行。在執行SQL語句前可監聽成功和失敗相關事件,只不過異步執行操作是在主程序線程之外,這樣在SQL執行時可以運行其他代碼。
下面的例子演示在數據庫存在時打開數據庫,反之創建新的數據庫文件:+展開-ActionScript
var db:File = File.applicationStorageDirectory.resolvePath("Authors.db");
var sqlConn:SQLConnection = new SQLConnection();
sqlConn.addEventListener( SQLEvent.OPEN, openHandler );
sqlConn.addEventListener( SQLErrorEvent.ERROR, errorHandler );
sqlConn.openAsync( db );
private function openHandler( evt:SQLEvent ):void {
trace( "Database created.");
}
private function errorHandler( evt:SQLErrorEvent ):void {
trace( "Error"+ evt.error.message + "::"+evt.error.details );
}
如果之前沒有創建過Authors.db,則SQLConnection實例的openAsync方法會在應用程序存儲目錄創建這個數據庫文件。如果操作成功,一個SQLEvent對象發出并調用openHandler 方法。
如果操作中出現錯誤,一個SQLErrorEvent被發出。SQLErrorEvent對象的error屬性是一個SQLError對象繼承自flash.errors.Error類。
要執行SQL語句,先賦值申明的SQL字符串值傳遞給SQLStatement的text屬性并調用execute方法。下面的例子使用SQL語言的CREATE TABLE語句在數據庫里創建一個新表:+展開-ActionScript
var db:File =File.applicationStorageDirectory.resolvePath( "Authors.db");
var sqlConn:SQLConnection = new SQLConnection();
sqlConn.addEventListener( SQLEvent.OPEN, openHandler );
sqlConn.addEventListener( SQLErrorEvent.ERROR, errorHandler );
sqlConn.openAsync( db );
private function openHandler( evt:SQLEvent ):void {
var sql:String = "CREATE TABLE IF NOT EXISTS authors ("+"authorId INTEGER PRIMARY KEY,"
+"firstName TEXT NOT NULL,"
+"lastName TEXT NOT NULL"+");";
var statement:SQLStatement = new SQLStatement();
statement.sqlConnection = sqlConn;
statement.text = sql;
statement.addEventListener( SQLEvent.RESULT, resultHandler );
statement.addEventListener(SQLErrorEvent.ERROR,errorHandler );
statement.execute();
}
private function resultHandler( evt:SQLEvent ):void {
trace ( "Table created." );
}
private function errorHandler( evt:SQLErrorEvent ):void {
trace ( "Error"+ evt.error.message +"::"+ evt.error.details );
}
當數據庫連接被打開時,SQL語句被執行,創建了一個新的authors表,列名分別為authorId,firstName, 和lastName。SQLStatement對象通過其sqlConnection屬性獲得SQLConnection實例,在執行之前要注冊相應的事件監聽器。因為這里使用的是異步的openAsync方法,這樣在執行異步方法時,其他操作也會繼續被執行,不會被阻塞。
使用SQL聲明性語言執行查詢,除了CREATE TABLE 命令外,還有INSERT, SELECT,UPDATE, 和DELETE查詢語句。下面的代碼執行INSERT語句添加數據:+展開-ActionScript
private var insertQuery:SQLStatement = new SQLStatement();
private function addAuthor( fName:String, lName:String ):void {
var sql:String = "INSERT INTO authors VALUES ("+"null,"+"'"+ fName + "',"+"'"+ lName + "'"+");";
insertQuery.sqlConnection = sqlConn;
insertQuery.text = sql;
insertQuery.addEventListener( SQLEvent.RESULT, insertHandler );
insertQuery.addEventListener( SQLErrorEvent.ERROR,errorHandler );
insertQuery.execute();
}
private function insertHandler( evt:SQLEvent ):void {
var result:SQLResult = insertQuery.getResult();
trace( "Row ID:"+ result.lastInsertRowID + "/"+"#Rows Affected:"+ result.rowsAffected );
}
使用INSERT INTO SQL語句Author數據被添加到authors數據庫表中。如果操作成功,insertHandler方法被調用,SQLStatement實例的getResult方法收到SQLResult對象。
要簡化和增強執行查詢語句的性能,SQLStatement類提供了一個parameters屬性和itemClass屬性。像這里的情況,一個同樣的Insert語句可能使用不同的插入內容調用很多次,這時候就可以使用SQLStatemnt的parameters屬性,parameters屬性是一個關聯數組,使用命名的和未命名的參數存儲鍵---值對。
下面的例子使用命名參數:+展開-ActionScript
var insertSql:String = "INSERT INTO authors VALUES ("+"null,:firstName,:lastName);";
insertQuery.sqlConnection = sqlConn;
insertQuery.text = insertSql;
insertQuery.parameters[":firstName"] = fName;
insertQuery.parameters[":lastName"] = lName;
當語句被執行前,這些值被替換,你可以在屬性名前使用:或@符號,也可以是數字索引作為屬性名,SQL語句里用?取代:+展開-ActionScript
var insertSql:String = "INSERT INTO authors VALUES("+"null,?,?);";
insertQuery.sqlConnection = sqlConn;
insertQuery.text = insertSql;
insertQuery.parameters[1] = lName;
當執行語句時每個索引下的值會替換掉SQL語句中的?符號。這樣做的好處是不僅提高了執行效率,而且提高了抵御如SQL注入等惡意攻擊。
如果你的程序有個數據對象關聯到本地數據庫的表數據,那么通過SQLStatement的itemClass屬性可以很方便的映射SELECT查詢獲得的行數據結果。下面的例子代碼使用itemClass屬性映射com.oreilly.flexcookbook.Author類返回的author數據:+展開-ActionScript
import com.oreilly.flexcookbook.Author;
private var selectQuery:SQLStatement = new SQLStatement();
private function getAuthors():void {
var sql:String = "SELECT authorId,firstName,lastName FROM authors";
selectQuery.sqlConnection = sqlConn;
selectQuery.text = sql;
selectQuery.itemClass = Author;
selectQuery.addEventListener( SQLEvent.RESULT, selectHandler );
selectQuery.addEventListener( SQLErrorEvent.ERROR,errorHandler );
selectQuery.execute();
}
private function selectHandler( evt:SQLEvent ):void {
var authors:Array = selectQuery.getResult().data;
for( var i:int = 0; i < authors.length; i++ ){
var author:Author = authors[i] as Author;
trace( author.firstName + " "+ author.lastName );
}
}
當查詢成功時,selectHandler方法被調用,SQLStatement實例的getResult方法得到SQLResult對象,SQLResult對象的data屬性是一個數據庫行記錄數組,數組中的每個元素被映射為Author對象,因為Author類已提供給itemClass屬性。
關于SQL語言已經有很多書可以查閱,本節重點介紹在本地數據庫執行查詢語句。