AIR 创建数据库和表,以及同步和异步执行模式
本章主要总结关系数据库引擎(sqlite),同步和异步执行模式,创建数据库和表
Adobe AIR 包括一个基于 SQL 的关系数据库引擎(sqlite),该引擎在运行时中运行,数据以本地方式存储在运行 AIR 应用程序的计算机上的数据库文件中(例如,在计算机的硬盘驱动器上)。由于数据库的运行和数据文件的存储都在本地进行,因此,不管网络连接是否可用,AIR 应用程序都可以使用数据库。
单个 Adobe AIR 本地 SQL 数据库作为单个文件存储在计算机的文件系统中。运行时包括 SQL 数据库引擎,该引擎管理数据库文件的创建和结构化以及操作和检索数据库文件中的数据。运行时不指定在文件系统上存储数据库数据的方式或位置;相反,每个数据库完全存储在单个文件中。您指定在文件系统中存储数据库文件的位置。单个 AIR 应用程序可以访问一个或多个单独的数据库(即单独的数据库文件)。由于运行时将每个数据库作为单个文件存储在文件系统上,因此可以在需要时按照应用程序的设计和操作系统的文件访问约束查找您的数据库。每个用户都可以具有其特定数据的单独数据库文件,或者数据库文件可以由在单个计算机上共享数据的所有应用程序用户访问。由于数据对单个计算机是本地的,因此在不同计算机上的用户之间并不自动共享数据。本地 SQL 数据库引擎未提供对远程数据库或基于服务器的数据库执行 SQL 语句的任何功能。
关于sqlite
关于SQLite的特性:
1. ACID事务
2. 零配置 – 无需安装和管理配置
3. 储存在单一磁盘文件中的一个完整的数据库
4. 数据库文件可以在不同字节顺序的机器间自由的共享
5. 支持数据库大小至2TB
6. 足够小, 大致3万行C代码, 250K
7. 比一些流行的数据库在大部分普通数据库操作要快
8. 简单, 轻松的API
9. 包含TCL绑定, 同时通过Wrapper支持其他语言的绑定
10. 良好注释的源代码, 并且有着90%以上的测试覆盖率
11. 独立: 没有额外依赖
12. Source完全的Open, 你可以用于任何用途, 包括出售它
13. 支持多种开发语言,C, PHP, Perl, Java, ASP.NET,Python
更详细情况可以参考以下站点:
http://www.sqlite.org/
http://www.sqlite.com.cn/
本地 SQL 数据库的用途
AIR 本地 SQL 数据库功能可以用于将应用程序数据存储在用户的本地计算机上的任何目的。Adobe AIR 包括在本地存储数据的几种机制,各机制具有不同的优点。以下是本地 SQL 数据库在 AIR 应用程序中的一些可能用途:
1.对于面向数据的应用程序(例如通讯簿),数据库可以用于存储主应用程序数据。
2.对于面向文档的应用程序(用户创建要保存并可能共享的文档),可以在用户指定的位置将每个文档另存为数据库文件。(但是,请注意,任何 AIR 应用程序都能够打开数据库文件,因此对于潜在敏感的文档,建议使用单独的加密机制。)
3.对于支持网络的应用程序,数据库可以用于存储应用程序数据的本地缓存,或者在网络连接不可用时暂时存储数据。可以创建一种将本地数据库与网络数据存储同步的机制。
4.对于任何应用程序,数据库都可以用于存储单个用户的应用程序设置,例如用户选项或应用程序信息(如窗口大小和位置)。
关于同步和异步执行模式
1.编写代码以处理本地 SQL 数据库时,会指定以两种执行模式之一执行数据库操作:异步或同步执行模式。通常,代码示例说明如何以这两种方式执行每个操作,以便您可以使用最适合您需求的示例。
2.在异步执行模式中,为运行时提供一个指令,运行时将在请求的操作完成或失败时调度事件。首先,通知数据库引擎执行操作。在应用程序继续运行的同时,数据库引擎在后台工作。最后,完成操作时(或者它失败时),数据库引擎调度事件。由事件触发的代码执行后续操作。此方法具有一个重要的优点:运行时在后台执行数据库操作,同时主应用程序代码继续执行。如果数据库操作花费大量的时间,则应用程序继续运行。最重要的是,用户可以继续与其交互,而屏幕不会冻结。但是,与其它代码相比,编写异步操作代码可能更加复杂。在必须将多个相关的操作分配给各个事件侦听器方法的情况下,通常会出现此复杂性。
3.从概念上说,将操作作为单个步骤序列(一组同步操作,而不是分到几个事件侦听器方法中的一组操作)进行编码更为简单。除了异步数据库操作外,Adobe AIR 还允许您同步执行数据库操作。在同步执行模式中,操作不在后台运行。相反,它们以与所有其它应用程序代码相同的执行序列运行。通知数据库引擎执行操作。然后,代码在数据库引擎工作时暂停。完成操作后,继续执行下一行代码。
4.异步还是同步执行操作是在 SQLConnection 级别上设置的。使用单个数据库连接,无法同步执行某些操作或语句,同时异步执行其它操作或语句。通过调用 SQLConnection 方法打开数据库,可以指定 SQLConnection 是在同步还是异步执行模式下操作。如果调用 SQLConnection.open(),则连接在同步执行模式下操作;如果调用 SQLConnection.openAsync(),则连接在异步执行模式下操作。使用 open() 或 openAsync() 将 SQLConnection 实例连接到数据库后,除非先关闭再重新打开到数据库的连接,否则该实例将固定为同步或异步执行模式。
创建数据库
若要创建数据库文件,请首先创建 SQLConnection 实例。调用其 open() 方法在同步执行模式下打开它,或者调用其 openAsync() 方法在异步执行模式下打开它。open() 和 openAsync() 方法用于打开到数据库的连接。如果传递的 File 实例引用 reference 参数(第一个参数)的不存在的文件位置,则 open() 或 openAsync() 方法将在该文件位置创建一个数据库文件,并打开到新创建的数据库的连接。
不管是调用 open() 方法还是 openAsync() 方法创建数据库,数据库文件的名称都可以是具有任何文件扩展名的任何有效文件名。如果调用 reference 参数为 null 的 open() 或 openAsync() 方法,则将创建新的内存中数据库,而不是在磁盘上创建数据库文件。
以下代码清单说明使用异步执行模式创建数据库文件(新数据库)的过程,数据库文件保存在应用程序的存储目录中,其文件名为“myTestdb.db”:
import mx.controls.Alert;
private var con:SQLConnection;
private function initApp():void
{
var file:File = File.applicationStorageDirectory.resolvePath("myTestdb.db")
con = new SQLConnection();
//在 openAsync() 方法调用操作成功完成时调度
con.addEventListener(SQLEvent.OPEN,openHandler);
//SQLConnection 对象的异步操作导致错误时调度
con.addEventListener(SQLErrorEvent.ERROR,errorHandler);
con.openAsync(file);
}
private function openHandler(evt:SQLEvent):void
{
Alert.show("成功完成");
}
private function errorHandler(evt:SQLErrorEvent):void
{
Alert.show("失败");
Alert.show(evt.error.message);
Alert.show(evt.error.details);
}
要同步执行操作,请在使用 SQLConnection 实例打开数据库连接时,调用 open() 方法。以下代码说明如何创建和打开同步执行其操作的 SQLConnection 实例:
import mx.controls.Alert;
private var con:SQLConnection;
private function initApp():void
{
var file:File = File.applicationStorageDirectory.resolvePath("myTestdb.db")
con = new SQLConnection();
try
{
con.open(file);
Alert.show("成功完成");
}
catch(error:SQLError)
{
Alert.show(error.message);
Alert.show(error.details);
}
}
创建数据库表
以下使用异步执行模式在现有数据库文件中创建一个名为“emp”的表。
import mx.controls.Alert;
private var con:SQLConnection;
private var createStmt:SQLStatement;
private function initApp():void
{
var file:File = File.applicationStorageDirectory.resolvePath("myTestdb.db")
con = new SQLConnection();
//在 openAsync() 方法调用操作成功完成时调度
con.addEventListener(SQLEvent.OPEN,openHandler);
//SQLConnection 对象的异步操作导致错误时调度
con.addEventListener(SQLErrorEvent.ERROR,errorHandler);
con.openAsync(file);
}
private function createResult(event:SQLEvent):void
{
Alert.show("表创建");
}
private function createError(event:SQLErrorEvent):void
{
Alert.show("Error message:", event.error.message);
Alert.show("Details:", event.error.details);
}
private function openHandler(evt:SQLEvent):void
{
Alert.show("成功完成");
createStmt = new SQLStatement();
createStmt.sqlConnection = con;
var sql:String =
"CREATE TABLE IF NOT EXISTS emp (" +
" empId INTEGER PRIMARY KEY AUTOINCREMENT, " +
" firstName TEXT, " +
" lastName TEXT, " +
" salary NUMERIC CHECK (salary > 0)" +
")";
createStmt.text = sql;
createStmt.addEventListener(SQLEvent.RESULT, createResult);
createStmt.addEventListener(SQLErrorEvent.ERROR, createError);
createStmt.execute();
}
private function errorHandler(evt:SQLErrorEvent):void
{
Alert.show("失败");
Alert.show(evt.error.message);
Alert.show(evt.error.details);
}
以下代码使用同步执行模式在现有数据库文件中创建一个名为“emp”的表
import mx.controls.Alert;
private var con:SQLConnection;
private var createStmt:SQLStatement;
private function initApp():void
{
var file:File = File.applicationStorageDirectory.resolvePath("myTestdb.db")
con = new SQLConnection();
createStmt = new SQLStatement();
try
{
con.open(file);
createStmt.sqlConnection = con;
var sql:String =
"CREATE TABLE IF NOT EXISTS emp (" +
" empId INTEGER PRIMARY KEY AUTOINCREMENT, " +
" firstName TEXT, " +
" lastName TEXT, " +
" salary NUMERIC CHECK (salary > 0)" +
")";
createStmt.text = sql;
createStmt.execute();
Alert.show("成功完成");
}
catch(error:SQLError)
{
Alert.show(error.message);
Alert.show(error.details);
}
}
代码下载:
https://files.cnblogs.com/aierong/Air_Test_SQLite.rar
本章主要总结数据库的插入,删除,修改,以及语句参数的使用
本章提到的同步和异步操作,不明白的可以看上篇文章
http://www.cnblogs.com/aierong/archive/2009/01/22/flex_Sqlite_1.html
0.SQLStatement类介绍
SQLStatement实例用于针对通过 SQLConnection 实例打开的本地 SQL 数据库执行 SQL 语句。
SQLStatement实例通过将 SQLConnection 实例设置为 SQLStatement 实例的 sqlConnection 属性的值来链接到 SQLConnection 实例。text 属性用要执行的 SQL 语句的实际文本进行填充。如有必要,可以使用 parameters 属性指定 SQL 语句参数的值,并通过调用 execute() 方法执行该语句。
1.插入数据
同步版本:
import mx.controls.Alert;
private var con:SQLConnection;
private function initApp():void
{
var file:File = File.applicationStorageDirectory.resolvePath("myTestdb.db")
con = new SQLConnection();
var stmt:SQLStatement = new SQLStatement();
try
{
con.open(file);
stmt.sqlConnection = con;
stmt.text="INSERT INTO emp (firstName, lastName, salary) VALUES ('f', 'l', 88)";
stmt.execute();
}
catch(error:SQLError)
{
Alert.show(error.message);
Alert.show(error.details);
}
}
代码说明:
SQLStatement类的实例用于针对通过 SQLConnection 实例打开的本地 SQL 数据库执行 SQL 语句
2.得到已插入行的数据库生成的行标识
得到自动增长列的行标识数值
var stmt:SQLStatement = new SQLStatement();
stmt.sqlConnection = con;
stmt.text="INSERT INTO emp (firstName, lastName, salary) VALUES ('f', 'l', 88)";
stmt.execute();
var result:SQLResult = stmt.getResult();
var primaryKey:Number = result.lastInsertRowID;
Alert.show(primaryKey.toString());
代码说明:
SQLResult 类提供对为响应 SQL 语句(SQLStatement 实例)执行而返回的数据的访问
lastInsertRowID属性:上次生成的行标识符(由 SQL INSERT 语句生成),如果执行的语句不是 INSERT 语句,则该值为 0。
3.语句参数的使用
在多次使用一个 SQL 语句但该语句中的值不同的情况下,最佳方法是使用包括参数的 SQL 语句而不是在 SQL 文本中包括字面值。参数是语句文本中的一个占位符,每次执行语句时都将它替换为实际的值。
参数名称由“:”或“@”字符后跟一个名称组成,例如::itemName @firstName
还可以使用未命名参数,使用“?”字符表示 SQL 语句中的参数。按照参数在语句中的顺序,每个参数都分配有一个数字索引,数字索引从索引 0(表示第一个参数)开始。
使用参数的优点:
1.性能更佳
2.显式数据类型指定
3.安全性更高
实例代码:得到自动增长列的行标识数值(异步版本)
private var stmt1:SQLStatement;
private function GetlastInsertRowID():void
{
stmt1 = new SQLStatement();
stmt1.sqlConnection = con;
stmt1.text="INSERT INTO emp (firstName, lastName, salary) VALUES (@firstName, @lastName, @salary)";
stmt1.parameters["@firstName"]="f";
stmt1.parameters["@lastName"]="l";
stmt1.parameters["@salary"]=88;
stmt1.addEventListener(SQLEvent.RESULT,okHandler);
stmt1.addEventListener(SQLErrorEvent.ERROR,errorHandler);
stmt1.execute();
}
private function okHandler(evt:SQLEvent):void
{
Alert.show("插入成功");
var re:SQLResult= this.stmt1.getResult();
var id:Number=re.lastInsertRowID;
Alert.show(id.toString());
}
private function errorHandler(evt:SQLErrorEvent):void
{
Alert.show("失败");
Alert.show(evt.error.message);
Alert.show(evt.error.details);
}
代码说明:
此例题中用到了语句参数@firstName, @lastName, @salary,并分别赋值
要是使用未命名参数,把代码修改如下即可(注意数字索引从0开始):
stmt1.text="INSERT INTO emp (firstName, lastName, salary) VALUES (?, ?, ?)";
stmt1.parameters[0]="f";
stmt1.parameters[1]="l";
stmt1.parameters[2]=88;
4.删除操作
private function del():void
{
var stmt:SQLStatement = new SQLStatement();
stmt.sqlConnection = con;
stmt.text="delete from emp where salary=:salary";
stmt.parameters[":salary"]=88;
stmt.execute();
var result:SQLResult = stmt.getResult();
var count:Number = result.rowsAffected;
Alert.show("成功删除"+count.toString()+"行");
}
代码说明:
rowsAffected属性:指示受此操作影响的行数
请注意,当相关的 SQL 操作为不带 WHERE 子句的 DELETE 语句时(即该语句删除表中的所有行),rowsAffected 属性始终为 0,而不管删除了多少行。如果您需要知道删除的行数,则可以包括 WHERE 子句 WHERE 1 = 1,在这种情况下,将删除所有行,并且 rowsAffected 属性会精确反映已删除的行数
5.修改操作
private function updateData():void
{
var stmt:SQLStatement = new SQLStatement();
stmt.sqlConnection = con;
stmt.text="update emp set lastName=:lastName where salary=:salary";
stmt.parameters[":lastName"]="la";
stmt.parameters[":salary"]=88;
stmt.execute();
var result:SQLResult = stmt.getResult();
var count:Number = result.rowsAffected;
Alert.show("成功修改"+count.toString()+"行");
}
代码说明:
把salary=88的lastName修改为"la"
6.代码下载
https://files.cnblogs.com/aierong/Air_Test_SQLite2.rar
本章主要总结表的查询
1.查询
同步版本:
private function query():void
{
var stmt:SQLStatement = new SQLStatement();
stmt.sqlConnection = con;
stmt.text = "select empId,firstName,lastName,salary from emp";
stmt.execute();
var result:SQLResult = stmt.getResult();
if ( result.data!=null )
{
var numResults:int =result.data.length;
for (var i:int = 0; i < numResults; i++)
{
var row:Object = result.data[i];
var output:String = "empId: " + row.empId;
output += "; firstName: " + row.firstName;
output += "; lastName: " + row.lastName;
output += "; salary: " + row.salary;
Alert.show(output);
}
}
}
代码说明:
getResult ()方法:执行结果的SQLResult对象的访问
SQLResult的data属性:执行语句而返回的数据。如果某一语句不返回任何数据,则此属性为 null。这就是本代码需要判断是否为空的目的。
2.查询部分结果
默认情况下,执行 SELECT 语句会一次检索结果集的所有行,有时我们需要查询第1行怎么办?
查询第1行的异步版本实例代码如下:
private var responder:Responder;
private var stmt:SQLStatement;
private function querytop1():void
{
stmt = new SQLStatement();
stmt.sqlConnection = con;
stmt.text = "select empId,firstName,lastName,salary from emp where firstName=:firstName";
stmt.parameters[":firstName"]="f";
responder= new Responder(resultHandler, errorHandler);
stmt.execute(1,responder);
}
private function resultHandler(result:SQLResult):void
{
if ( result.data!=null )
{
var numResults:int =result.data.length;
for (var i:int = 0; i < numResults; i++)
{
var row:Object = result.data[i];
var output:String = "empId: " + row.empId;
output += "; firstName: " + row.firstName;
output += "; lastName: " + row.lastName;
output += "; salary: " + row.salary;
Alert.show(output);
}
}
}
private function errorHandler(error:SQLError):void
{
Alert.show(error.message);
Alert.show(error.details);
}
代码说明:
execute () 方法参数说明:
第1个参数:此值指示该语句一次返回的行数。默认值为 -1,指示一次返回所有结果行,
第2个参数:一个Responder对象,指定操作成功或失败时要调用的方法。
实际在本例中,也可以不用Responder对象,而用事件侦听器执行SQLStatement,以确定语句的执行何时完成或失败
stmt.addEventListener(SQLEvent.RESULT,resultHandler);
stmt.addEventListener(SQLErrorEvent.ERROR,errorHandler);
具体代码实现可以参照以前的文章
3.代码下载
https://files.cnblogs.com/aierong/Air_Test_SQLite3.rar
本章主要总结数据操作中的事务控制
由于SQLite中SQL语句不支持事务,我们可以通过SQLConnection类的与事务相关的方法可使用此功能:SQLConnection.begin()、SQLConnection.commit() 和 SQLConnection.rollback()来实现事务功能。
关于air本地数据库中的SQL支持可以参考
http://help.adobe.com/zh_CN/AIR/1.5/jslr/index.html?localDatabaseSQLSupport.html
事务实例代码:
import mx.controls.Alert;
private var con:SQLConnection;
private function initApp():void
{
var file:File = File.applicationStorageDirectory.resolvePath("myTestdb.db")
con = new SQLConnection();
var stmt:SQLStatement = new SQLStatement();
try
{
con.open(file);
con.begin();
stmt.sqlConnection=con;
stmt.text="INSERT INTO emp (firstName, lastName, salary) VALUES ('f', 'l', 1110)";
stmt.execute();
con.commit();
}
catch(err:SQLError)
{
con.rollback();
Alert.show(err.message);
}
}
代码说明:
事务由begin方法开始,其间运行的n个sql语句要是成功,就由commit方法提交,其间要是有任何一个sql语句发生错误,就由rollback方法全部回滚.代码比较简单,有其他语言开发建议的人一眼就可以看明白。
代码下载:
https://files.cnblogs.com/aierong/Air_Test_SQLite4.rar
A.Flex Air开发SQLite小结
1.sqlite各语句间用分号间隔
例如:select * from tablea;select * from tableb;
2.关于Flex中用一个SQLStatement执行多条SQL的代码的问题
有些时候我们可能一次执行多条SQL,不过比较遗憾的是一个SQLStatement只会执行第一个SQL。
下面是一段简单的代码可以帮你解决这个问题,不过需要在SQL件用’;'划分:
try {
// Separate all statements
var parts:Array = createSQL.split( ');' );
for( var i:int; i<parts.length; i++ ) {
// Only, if we really have an SQL statement
if ( '' != parts[i] ) {
createStmt.text = parts[i] + ');';
createStmt.execute();
}
}
} catch( error:SQLError ) {
// something failed...
}
具体文章可以看
B.SQLite开发工具
SQLite Spy
http://www.yunqa.de/delphi/sqlitespy
一个非常不错的SQLite Database Explorer and Query Analyzer。不需要安装。 强烈推荐这个,我自己也用.
DBTools Manager
有免费版本的多数据库管理器,同时支持SQLite
Aqua Data Studio
有很多功能支持很多数据库的一个软件,可以通过JDBC或ODBC来支持SQLite查询。
还有SQLite Administrator,后来发现Firefox的插件(addons) Sqlite Manager也是不错的选择。
C.SQLite与Sql Server的语法差异
1.返回最后插入的标识值
返回最后插入的标识值sql server用@@IDENTITY
sqlite用标量函数LAST_INSERT_ROWID()
返回通过当前的 SQLConnection 插入到数据库的最后一行的行标识符(生成的主键)。此值与 SQLConnection.lastInsertRowID 属性返回的值相同。
2.top n
在sql server中返回前2行可以这样:
select top 2 * from aa
order by ids desc
sqlite中用LIMIT,语句如下:
select * from aa
order by ids desc
LIMIT 2
3.GETDATE ( )
在sql server中GETDATE ( )返回当前系统日期和时间
sqlite中没有
4.EXISTS语句
sql server中判断插入(不存在ids=5的就插入)
IF NOT EXISTS (select * from aa where ids=5)
BEGIN
insert into aa(nickname)
select 't'
END
在sqlite中可以这样
insert into aa(nickname)
select 't'
where not exists(select * from aa where ids=5)
5.嵌套事务
sqlite仅允许单个活动的事务
6.RIGHT 和 FULL OUTER JOIN
sqlite不支持 RIGHT OUTER JOIN 或 FULL OUTER JOIN
7.可更新的视图
sqlite视图是只读的。不能对视图执行 DELETE、INSERT 或 UPDATE 语句,sql server是可以对视图 DELETE、INSERT 或 UPDATE
最后推荐几个好站点对开发sqlite有帮助:
sqlite官方站
http://www.sqlite.org/lang.html
sqlite中文站
Adobe AIR 包括创建和使用本地 SQL 数据库的功能
http://help.adobe.com/zh_CN/AIR/1.5/devappshtml/WS5b3ccc516d4fbf351e63e3d118676a5497-7fb4.html
http://help.adobe.com/zh_CN/AIR/1.5/jslr/index.html?localDatabaseSQLSupport.html
posted on 2011-08-26 16:46 破阵子 . 如是我闻 阅读(617) 评论(0) 编辑 收藏 举报