首页 > 移动开发 > Android > 正文
2.2.1 SQLite命令行
2015-04-22 13:59:51     我来说两句      
收藏    我要投稿
也许,介绍SQLite及其奇特之处的最好方法是使用它。为了真实性,整个示例记录在Android模拟器:一个Android虚拟设备(AVD)上。代码清单2-4的第1行代码启动模拟器实例,使用先前创建的设备配置tablet。在这个示例中,该配置运行的是Android Ice Cream Sandwich,release 15,V4.0.3。这个示例在大多数其他版本的Android或Android真机设备上看起来几乎相同。对于这个问题,在安装了sqlite3的任何其他类UNIX系统的命令行看起来应该都一样。

注意:sglite3程序仅适用于Android的“工程”版本。模拟器使用的是工程版本,但多数产品设备(如手机)采用的Android是大幅简化版本。产品版本安装了较少的调试工具,从而让用户有更多的空间来存放数据,并使它们能避免数据被破坏。

SQLite数据库是一个简单的文件。在Android设备上大多数应用程序把数据库存储在它们的文件系统沙箱中,位于名为databases的子目录中。例如,对于包名是com.enterpriseandroid. contacts.webdataContacts的应用程序,其数据库极有可能位于目录/data/data/com.enterprise- android. contacts.webdataContacts/databases中。当然,应用程序通过把它的数据库放在公共存储区域,无法共享对数据库的访问(例如,存储在/sdcard文件系统的任何数据,对任何应用程序都是公开的)。但是,正如你在第3章将看到的,相比通过使数据库本身全局可用这种方法,还有很多更好的方法来共享数据。

该示例还演示了如何使用adb工具,它是Android SDK中的Android调试器。adb是Android工具中的瑞士军刀。它位于SDK(在本例中,使用shell变量$ANDROID_HOME定位SDK目录)中的platform-tools目录。运行时,adb连接到一个运行Android系统的守护进程。在本例中,它连接到上面命令行启动的模拟器。为了在模拟器上显示shell提示符,使用命令adb shell。

在shell提示符下,可以运行SQLite的命令行实用程序sglite3。代码清单2-4使用已安装的包名是com.enterpriseandroid.contacts.dbDemo的应用程序的文件系统沙箱。

 

代码清单2-4:启动sqlite3
wiley> $ANDROID_HOME/sdk/tools/emulator -avd tablet &
wiley> $ANDROID_HOME/sdk/platform-tools/adb shell
# cd /data/data/com.enterpriseandroid.contacts.dbDemo/databases
# sqlite3 demo.db
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite>
在命令行中使用sqlite3,首先需要记住的是,每条命令必须以分号结束,如代码清单2-5所示。
代码清单2-5:使用分号结束sqlite3命令
sqlite> select * whoops typo
   ...>
   ...> ;
Error: near "whoops": syntax error

除非sqlite3碰到结束语句的分号,否则它把所有输入作为一条单独的SQL语句解释,并提供继续提示符...> 。只有碰到分号之后,它才对输入进行解析和求值,并传递任何必要的错误消息。

当使用sqlite3工作时,还有一些非常有用的元命令(meta-command,不是SQL语言的一部分)。元命令都是以句点开头的命令。它们不会被解释为SQL,而是作为sqlite3命令行程序的命令。其中最重要的两个是.help和.exit。

●.exit命令退出sqlite3的命令解释程序。

.help命令输出其他“点”命令的列表。

注意:也可以通过按Ctrl+D快捷键终止SQLite的命令行会话。即使命令解析器完全乱了,这也管用。

SQLite语法支持多种数据类型:TINYINT、BIGINT、FLOAT(7,3)、LONGVARCHAR和SMALLDATETIME等。然而,如前所述,列的类型实际上仅仅是注释。代码清单2-6通过存储字符串值“la”到非文本类型的几列中,演示了这一点。
 

代码清单2-6:sqlite3的数据类型 
sqlite> create table test (
   ...> c1 biginteger, c2 smalldatetime, c3 float(9, 3));
sqlite> insert into test values("la", "la", "la");
sqlite> select * from test;
la|la|la

列类型仅作为提示,以帮助SQLite为存储在该列中的数据选择高效的内部表示。SQLite使用一些简单规则来调节“类型相似性”,从而决定内部存储类型。这些规则几乎不可见,除了影响给定的数据集占用的磁盘数量之外。

注意:更多细节请查阅http://www.sqlite.org/datatype3.html#affinity

在实践中,许多开发人员限制自己只使用SQLite的4种基本的内部存储类型—— integer、real、text和blob—— 并显式使用文本表示时间戳以及使用整型表示布尔值。

有一些约束可以附加到列定义中。最重要的是PRIMARY KEY约束。表中每一行的主键列都是唯一值,它标识这一行。

SQLite支持非整数主键。它甚至还支持复合(多列)主键。然而,需要注意的是,非整数主键的主键列。除了指示UNIQUE约束(在本章后面介绍)之外,主键约束还意味着NOT NULL约束。遗憾的是,因为在早期版本中的疏忽,SQLite允许NULL作为非integer类型主键的值。因为每个NULL是不同的值(甚至不同于其他的NULL),所以SQLite允许主键列包含多个NULL值,从而允许表中存在无法通过其主键来区分的多行。

如代码清单2-7所示,默认情况下,整数主键列设置为自动递增。这意味着SQLite会为添加到数据库中的新行的主键列自动创建新值。为了使这一行为明确,声明列为PRIMARY KEY AUTOINCREMENT。

 

代码清单2-7:sqlite3的主键自动递增
sqlite> create table test (key integer primary key, val text);
sqlite> insert into test ( val ) values ("something");
sqlite> insert into test ( val ) values ("something else");
sqlite> select * from test;
1|something
2|something else
sqlite>

自动递增功能非常有用,因为通过它,数据库引擎本身保证了为新行创建的主键是唯一的。但是,它也提出了可导致丑陋和笨拙代码的问题。当添加一个新行添加到数据库中时,代码可能必须立即读取该新行,以便确定数据库赋给的主键值。

另一个可能出现在列定义中的重要约束是FOREIGN KEY。如前所述,默认情况下,SQLite不强制执行外键约束。类似列的类型,它本质上是一个注释,如代码清单2-8所示。

代码清单2-8:外键注释
sqlite> create table people (
   ...> name text, address integer references addresses(id));
sqlite> create table addresses (id integer primary key, street text);
sqlite> insert into people values("blake", 99);
sqlite> insert into addresses(street) values ("harpst");
sqlite> select * from people;
blake|99
sqlite> select * from addresses;
1|harpst
sqlite> select * from people, addresses where address = id;
sqlite>

在支持引用完整性的数据库中,第1个insert语句将失败,它违反外键约束。事实上,出于同样的原因,在第1个create table语句中试图创建表也将失败。

注意:在最新版本的Android中要启用引用完整性支持,使用指令:pragma FOREIGN_KEYS = true。

虽然SQLite不必强制执行引用完整性,但是一种复杂类型的、在一个表中定义,并且通过外键被其他内容引用的关系概念,是精心设计、易于修改和高效的数据存储的关键。当设计SQLite数据库时,鼓励开发人员使用标准最佳实践(如范式(normalization))。唯一的区别是访问数据库的代码必须准备自己执行引用完整性约束,而不是依赖于数据库来实现引用完整性。代码清单2-9扩充了示例代码清单2-8中的代码,展示了一个简单的连接。

 

代码清单2-9:一个简单的连接
sqlite> insert into addresses(street) values("pleasant");
sqlite> insert into addresses(street) values("western");
sqlite> insert into people values ("catherine", 2);
sqlite> insert into people values ("john", 3);
sqlite> insert into people values ("lenio", 3);
sqlite> select name,street from people, addresses where address = id;
catherine|pleasant
john|western
lenio|western

在这个示例中,有一个人住在Pleasant Street,而有两个住在Western Avenue。然而,addresses表中只有一条街道名为western的记录(record)。该数据没有重复。people表中的外键引用了保存了住在Western Avenue地址的两个人的同一个记录。

SQLite支持其他一些列约束,如代码清单2-10所示。

●unique:当这个约束应用于列时,SQLite将拒绝任何试图在表中添加将导致该列出现重复值的一行。

●not null:当这个约束应用于列时,SQLite将拒绝执行任何将导致行中该列为NULL的操作。

check(expression):当此约束应用于列时,每当一个新行添加到表中时,或当修改现有的行时,都会对表达式求值。如果求值的结果转换整数为0时,该操作将失败,操作被取消。如果表达式的计算结果为NULL或任何其他非零值,则操作成功。

代码清单2-10:列约束
sqlite>  create table test (
   ...> c1 text unique, c2 text not null, c3 text check(c3 in ("OK", 
"dandy")));
sqlite> insert into test values("dandy", "dandy", "dandy");
sqlite> insert into test values("dandy", "dandy", "dandy");
Error: column c1 is not unique
sqlite> insert into test values("dandy", null, "dandy");
Error: test.c2 may not be NULL
sqlite> insert into test values("dandy", "dandy", "bad");
Error: constraint failed
sqlite>



 



点击复制链接 与好友分享!回本站首页
分享到: 更多
您对本文章有什么意见或着疑问吗?请到论坛讨论您的关注和建议是我们前行的参考和动力  
上一篇:2.2 SQLite入门
下一篇:2.2.2 SQLite数据库示例
相关文章
图文推荐
排行
热门
文章
下载
读书

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训
版权所有: 红黑联盟--致力于做最好的IT技术学习网站