23.14.1.問題
我想讓應(yīng)用程序在本地保存和接收數(shù)據(jù)。
23.14.2.解決辦法
在用戶硬盤上創(chuàng)建數(shù)據(jù)庫(kù)文件,執(zhí)行SQL語句。
23.14.3.討論
Adobe AIR 運(yùn)行時(shí)引入了SQL數(shù)據(jù)庫(kù)引擎,使我們可以為創(chuàng)建本地?cái)?shù)據(jù)庫(kù)存儲(chǔ)信息。一個(gè)數(shù)據(jù)庫(kù)被保存為一個(gè)文件,且沒有限定存放于特定的目錄下,這樣可允許任何應(yīng)用程序都可訪問數(shù)據(jù)庫(kù)中的數(shù)據(jù)。AIR的SQL引擎可創(chuàng)建關(guān)系型數(shù)據(jù)庫(kù),用標(biāo)準(zhǔn)SQL語句存儲(chǔ)和接受復(fù)雜數(shù)據(jù)。
SQL 數(shù)據(jù)庫(kù)API 包含幾個(gè)類,提供創(chuàng)建和打開數(shù)據(jù)庫(kù),生成語句,監(jiān)聽操作事件,檢索有關(guān)數(shù)據(jù)庫(kù)的架構(gòu)信息。使用flash.filesystem.File類用合法的擴(kuò)展名創(chuàng)建數(shù)據(jù)庫(kù)文件。使用Flash.dataSQLConnection類的open和openAsync方法建立一個(gè)數(shù)據(jù)庫(kù)連接。如果你沒有傳遞File引用給open和openAsync方法,則會(huì)在內(nèi)存中創(chuàng)建一個(gè)數(shù)據(jù)庫(kù)并允許執(zhí)行SQL語句。SQL語句可被同步和異步執(zhí)行。在執(zhí)行SQL語句前可監(jiān)聽成功和失敗相關(guān)事件,只不過異步執(zhí)行操作是在主程序線程之外,這樣在SQL執(zhí)行時(shí)可以運(yùn)行其他代碼。
下面的例子演示在數(shù)據(jù)庫(kù)存在時(shí)打開數(shù)據(jù)庫(kù),反之創(chuàng)建新的數(shù)據(jù)庫(kù)文件:+展開-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 );
}
如果之前沒有創(chuàng)建過Authors.db,則SQLConnection實(shí)例的openAsync方法會(huì)在應(yīng)用程序存儲(chǔ)目錄創(chuàng)建這個(gè)數(shù)據(jù)庫(kù)文件。如果操作成功,一個(gè)SQLEvent對(duì)象發(fā)出并調(diào)用openHandler 方法。
如果操作中出現(xiàn)錯(cuò)誤,一個(gè)SQLErrorEvent被發(fā)出。SQLErrorEvent對(duì)象的error屬性是一個(gè)SQLError對(duì)象繼承自flash.errors.Error類。
要執(zhí)行SQL語句,先賦值申明的SQL字符串值傳遞給SQLStatement的text屬性并調(diào)用execute方法。下面的例子使用SQL語言的CREATE TABLE語句在數(shù)據(jù)庫(kù)里創(chuàng)建一個(gè)新表:+展開-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 );
}
當(dāng)數(shù)據(jù)庫(kù)連接被打開時(shí),SQL語句被執(zhí)行,創(chuàng)建了一個(gè)新的authors表,列名分別為authorId,firstName, 和lastName。SQLStatement對(duì)象通過其sqlConnection屬性獲得SQLConnection實(shí)例,在執(zhí)行之前要注冊(cè)相應(yīng)的事件監(jiān)聽器。因?yàn)檫@里使用的是異步的openAsync方法,這樣在執(zhí)行異步方法時(shí),其他操作也會(huì)繼續(xù)被執(zhí)行,不會(huì)被阻塞。
使用SQL聲明性語言執(zhí)行查詢,除了CREATE TABLE 命令外,還有INSERT, SELECT,UPDATE, 和DELETE查詢語句。下面的代碼執(zhí)行INSERT語句添加數(shù)據(jù):+展開-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數(shù)據(jù)被添加到authors數(shù)據(jù)庫(kù)表中。如果操作成功,insertHandler方法被調(diào)用,SQLStatement實(shí)例的getResult方法收到SQLResult對(duì)象。
要簡(jiǎn)化和增強(qiáng)執(zhí)行查詢語句的性能,SQLStatement類提供了一個(gè)parameters屬性和itemClass屬性。像這里的情況,一個(gè)同樣的Insert語句可能使用不同的插入內(nèi)容調(diào)用很多次,這時(shí)候就可以使用SQLStatemnt的parameters屬性,parameters屬性是一個(gè)關(guān)聯(lián)數(shù)組,使用命名的和未命名的參數(shù)存儲(chǔ)鍵---值對(duì)。
下面的例子使用命名參數(shù):+展開-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;
當(dāng)語句被執(zhí)行前,這些值被替換,你可以在屬性名前使用:或@符號(hào),也可以是數(shù)字索引作為屬性名,SQL語句里用?取代:+展開-ActionScript
var insertSql:String = "INSERT INTO authors VALUES("+"null,?,?);";
insertQuery.sqlConnection = sqlConn;
insertQuery.text = insertSql;
insertQuery.parameters[1] = lName;
當(dāng)執(zhí)行語句時(shí)每個(gè)索引下的值會(huì)替換掉SQL語句中的?符號(hào)。這樣做的好處是不僅提高了執(zhí)行效率,而且提高了抵御如SQL注入等惡意攻擊。
如果你的程序有個(gè)數(shù)據(jù)對(duì)象關(guān)聯(lián)到本地?cái)?shù)據(jù)庫(kù)的表數(shù)據(jù),那么通過SQLStatement的itemClass屬性可以很方便的映射SELECT查詢獲得的行數(shù)據(jù)結(jié)果。下面的例子代碼使用itemClass屬性映射com.oreilly.flexcookbook.Author類返回的author數(shù)據(jù):+展開-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 );
}
}
當(dāng)查詢成功時(shí),selectHandler方法被調(diào)用,SQLStatement實(shí)例的getResult方法得到SQLResult對(duì)象,SQLResult對(duì)象的data屬性是一個(gè)數(shù)據(jù)庫(kù)行記錄數(shù)組,數(shù)組中的每個(gè)元素被映射為Author對(duì)象,因?yàn)锳uthor類已提供給itemClass屬性。
關(guān)于SQL語言已經(jīng)有很多書可以查閱,本節(jié)重點(diǎn)介紹在本地?cái)?shù)據(jù)庫(kù)執(zhí)行查詢語句。