课程 1: 数据库基础

结束 Android 开发(入门)课程 的第三部分《访问网络》后,来到最后的第四部分《数据与数据库》,这部分课程要完成一个 Pets App,这个应用采用不同于之前的数据结构来构建,允许用户获取宠物的信息,并能够进行添加、更新、删除等操作。其中涉及到数据持久性的概念,用到了 SQLite 数据库等内容。

第四部分的课程分为四节课完成,每节课的内容如下:

  1. Intro to SQLite Databases
    介绍数据持久性的概念,以及 SQLite 数据库的基本操作。
  2. Databases in Android
    应用 Android 中的数据库。
  3. Content Providers
    通过内容提供器向数据库读取或添加数据。
  4. Finishing the App
    实现应用的更新和删除数据功能,最终完成应用开发。

这是第四部分《数据与数据库》的第一节课,导师是 Jessica Lin 和 Katherine Kuan。这节课的重点是练习 SQLite 数据库的操作。

关键词:数据持久性、SQLite 数据库、CRUD

数据持久性

之前课程中的应用都使用变量来保存数据,变量的生命周期与 Activity 紧密联系,当 Activity 被销毁时,变量也会被清除,存储在变量中的数据自然也随着被清除。显然,对于一些数据来说,例如应用的偏好设置、用户数据,需要永久保存下来,直到被主动删除,这就是数据持久性的概念。

计算机(包括手机、平板、电脑)通常有两种类型的存储器:临时存储器和永久存储器。临时存储器可理解为用于短期记忆,它适用于数值计算或屏幕显示等场景,特点是快速存取和生命周期短,例如 RAM 就是一种临时存储器;永久存储器可理解为用于长期记忆,它适用于保存用户数据,特点是数据可永久保持,但存取较慢,例如硬盘就是一种永久存储器。关于两种存储器更详细的介绍可参考这篇文章

Android 提供了多种永久存储数据的方法,包括将数据保存为文件放入设备存储器或上传至服务器;或者将数据保存至 SQLite 数据库;另外,应用的偏好设置也属于永久存储数据的一种方法,详细介绍可参考 这篇 Android Developers 文档

其中,将数据保存为文件的方法适用于大型的媒体文件,例如相机应用将照片保存为 png 文件,音乐应用将歌曲保存为 mp3 文件;偏好设置则可以顾名思义,用于保存应用的用户偏好设置,一般通过 SharedPreference 的键/值对保存原始类型数据或字符串;最后,SQLite 数据库适用于大规模且易于存取的格式化数据,这是接下来讨论的重点。

值得注意的是,一个 Android 应用通常不止使用一种永久存储数据的方法,例如相机应用将照片保存为文件的同时,也会将照片的拍摄时间、地点等详细信息保存至 SQLite 数据库。

SQLite 数据库

数据库是由特定结构组织的数据集合,使其数据可轻易操作和分析。SQLite 就是一种组织结构为一个或多个表格的数据库,一个表格是存储一种对象的列表,每一行表示一个对象,每一列表示对象的一个 state 或属性 (Attribute)。其中,SQL (Structured Query Language) 指结构化查询语言,与应用于 Android 的 XML 和 Java 相同,SQL 也是一种编程语言,专门用于数据库的表格创建,以及其中的条目添加、读取、更新、删除操作。SQLite 就是一种能够理解 SQL 语言的程序,

SQLite 是一种开源的轻量化数据库(对应 MySQL 重量级数据库),用于创建本地数据库,无需服务器。同时 SQLite 是 Android 自带的数据库,所以 Android 应用无需下载任何内容就可以直接使用 SQLite 数据库。这节课先在 Android 之外熟悉 SQLite,即在电脑的终端使用 SQLite。

Note:
MacBook 通常都预装了 SQLite。要查看系统是否预装了 SQLite,打开终端,输入 sqlite3,再按下 return 键。如果返回的结果中包含 SQLite 版本等信息,那么系统中就已经安装了 SQLite。具体的指令如下所示。

hsujin ~ $ sqlite3
SQLite version 3.19.3 2017-06-27 16:48:08
Enter ".help" for usage hints.
Connected to a transient in-memory database.
Use ".open FILENAME" to reopen on a persistent database.
sqlite> 

从上面的指令可以看到,在终端输入 sqlite3,并按下 return 键后,就启动了 sqlite3 程序,就可以开始操作数据库了。还有一种方法是在终端输入 sqlite3 shelter.db,即可启动 sqlite3 程序并直接打开指定的数据库文件,如果该文件不存在,则会创建一个新的数据库文件。

在 sqlite3 中包含两种指令,一种是 sqlite3 的程序指令,用于操作 sqlite3 软件本身,不属于 SQL 语言,特点是指令前面都有一个点 .,大小写敏感,例如

  1. .open shelter.db
    打开指定的数据库文件。如果该文件不存在,则会创建一个新的数据库文件。
  2. .quit
    退出 sqlite3 程序。
  3. .tables
    查看当前数据库中的所有表格。
  4. .schema ?PATTERN?
    查看创建指定表格的指令。
  5. .mode MODE ?TABLE?
    选择表格的输出模式,支持 csv,column,tabs 等格式。例如指令 .mode column 指定表格的输出模式为向左对齐的列,这样在输出表格时就清晰地把每一列显示出来,列之间用空格分隔。
  6. .headers on|off
    选择是否输出表格的表头,例如 .headers on 表示在输出表格时表头会显示出来。
  7. .help
    查看所有可用的程序命令。

另一种指令是 SQL 指令,即使用 SQL 语言来操作表格,对 SQLite 数据库表格的操作可以简单总结为 CRUD,表示 Create(添加)、Read(读取)、Update(更新)、Delete(删除)。指令大小写不敏感,但是为了区别 sqlite3 的程序指令,一般都保持全部大写的习惯。指令最后以分号 ; 结束,如果在 sqlite3 中输入 SQL 指令时没有添加分号,那么 sqlite3 会使指令头显示省略号 ...> 表示当前指令未输入完全,提示用户继续输入内容,直到 sqlite3 检测到分号。开发者可以利用这一点,在输入较长的指令时分成多行,使指令可视化。

常用的 SQL 指令可以参考这个 Cheatsheet,下面详细介绍每种指令的用法。

一、创建表格

CREATE TABLE pets (_id INTEGER PRIMARY KEY AUTOINCREMENT, 
                   name TEXT NOT NULL, 
                   breed TEXT NOT NULL, 
                   gender INTEGER NOT NULL, 
                   weight INTEGER NOT NULL DEFAULT 0);

使用 CREATE TABLE 关键字创建了一个名为 pets 的表格,有五个属性,分别为 _idnamebreedgenderweight 。其中,第一个属性为 _id,这是因为在一般情况下,每个对象都要有一个唯一识别码,下划线 _ 是 Android 的命名惯例。

对象的每个属性都需要指定一种存储类 (Storage Class)。这与 Java 变量需要指定一种数据类型不同,SQLite 采用了更宽泛的动态类型系统,即一个值的数据类型与值本身相关,例如 SQLite 的整数 (Integer) 存储类就包括了六种不同字节大小的整数数据类型。关于 SQLite 存储类的详细介绍可参考 这篇文章

SQLite 有五种存储类:

  1. NULL
    表示这个值为空值。
  2. INTEGER
    表示这个值为整数值,根据值的大小存储在 1,2,3,4,6,8 字节中。
  3. REAL
    表示这个值为浮点值。
  4. TEXT
    表示这个值为字符串,支持 UTF-8,UTF-16BE,UTF-16LE 编码方式。
  5. BLOB
    表示数据按输入的格式原样保存,例如图片、二进制数据等。

值得注意的是,SQLite 的存储类没有布尔类型,对于布尔类型数据的存储,通常用 INETGER 代替,例如 0 表示 false,1 表示 true。事实上,对于一些固定选项的数据,通常都用 INETGER 来存储,例如性别信息,可以使用 0 表示未知,1 表示男性,2 表示女性。这种做法使数据存储更准确,同时更节省存储空间。

上述代码,_id 属性指定为 INTEGER 存储类,表示每个对象的唯一识别码数值;name 属性指定为 TEXT 存储类,表示宠物名字的字符串;breed 属性指定为 TEXT 存储类,表示宠物种类的字符串;gender 属性指定为 INTEGER 存储类,表示宠物性别的数值代码,其中 0 表示未知,1 表示雄性,2 表示雌性;weight 属性指定为 INTEGER 存储类,表示宠物体重值。

在指定对象属性的存储类后,通常还会添加 SQL 关键字对属性作出限制,常用的关键字有

  1. PRIMARY KEY
    保证该属性的唯一性,一个表格中只能有一个属性应用这个 SQL 关键字。
  2. AUTOINCREMENT
    当表格添加新对象时,自动为该属性新增一个数值,通常用于 ID 属性。
  3. NOT NULL
    表示该属性不能为空,在表格添加新对象时必须带有该属性的值。
  4. DEFAULT <value>
    当表格添加新对象时,该属性如果没有输入值,那么就会采用指定的默认值。

上述代码,_id 属性带有 PRIMARY KEYAUTOINCREMENT 两个关键字,关键字之间用空格分隔,表示对象的唯一识别码,并且在添加新对象时,无需输入值,ID 值会自动加一,如果输入了已存在的 ID 值,sqlite3 会返回错误,保证 ID 值的唯一性;其余属性都带有 NOT NULL 关键字,表示该属性不能为空,在添加新对象时必须带有该属性的值;其中 weight 属性还带有 DEFAULT 0 关键字,表示如果没有输入宠物的体重值,那么就默认为零。

通过 SQL 指令 PRAGMA TABLE_INFO(?PATTERN?) 显示指定表格的属性信息,显示格式由 sqlite3 指令 .mode 决定,还可以使用 .headers on 指令使表头显示出来。

二、插入数据

INSERT INTO pets (_id, name, breed, gender, weight) 
          VALUES (1, "Tommy", "Pomeranian", 1, 4);

使用 INSERT INTO 关键字向 pets 表格添加了一个新对象,输入了每个属性的值,格式类似键/值对的形式,属性值按顺序放入 VALUES() 关键字内。对于未设置 NOT NULL 的属性,可以不输入值,例如根据创建表格时的设置,ID 值会在添加新对象时自动加一。注意指令最后添加分号。

三、读取数据

SELECT * FROM pets;

使用 SELECT 指令选中 pets 表格的所有列,其中 * 表示通配符,FROM 用于指定表格。sqlite3 返回的数据如下,显示格式设置为 .mode column ,并设置了 .headers on 显示表头。

_id         name        breed               gender      weight    
----------  ----------  ------------------  ----------  ----------
1           Tommy       Pomeranian Terrier  1           3         
2           Garfield    Tabby               1           4         
3           Binx        Bombay              1           7         
4           Lady        Cocker Spaniel      2           5         
5           Cat         Tabby               0           19         
6           Baxter      Border Terrier      1           6         
7           Arlene                          2           3   

如果要读取指定一行的数据,需要用到 WHERE 关键字,例如

SELECT name, breed FROM pets WHERE _id == 1;

sqlite3 会返回 ID 值为 1 的对象的 namebreed 两列,列之间用逗号 , 分隔,显示格式由 sqlite3 指令 .mode 决定,还可以使用 .headers on 指令使表头显示出来。

事实上,WHERE 关键字相当于一个条件语句,使 sqlite3 仅返回符合 WHERE 后面的条件的对象,例如指令 SELECT * FROM pets WHERE​ weight > 15; 仅返回体重为 15 以上的宠物信息。

除了 WHERE 条件语句外,还可以用 ORDER BY 关键字对读取的数据进行排序,例如

SELECT name, weight FROM pets WHERE gender == 1 ORDER BY weight DESC;

sqlite3 会返回雄性宠物的名字和体重两列,按照体重大小降序排列。其中 DESC 表示降序,ASC 表示升序。

四、更新数据

UPDATE pets SET weight = 18 WHERE _id = 5;

使用 UPDATE 关键字将 ID 值为 5 的宠物体重设置为 18,其中 SET 关键字实现属性的更新设置;WHERE 关键字作为条件语句指定要更新的对象,如果更新指令没有 WHERE 条件,那么更新的作用域会是整个表格,即更新表格内的所有对象。

五、删除数据

DELETE FROM pets WHERE _id = 1;

使用 DELETE FROM 关键字将 pets 表格内 ID 值为 1 的对象删除,这里同样用到了 WHERE 关键字作为条件语句指定要删除的对象,如果删除指令没有 WHERE 条件,那么就会删除表格内的所有对象,所以使用这条指令要谨慎。

六、删除表格

DROP TABLE pets;

使用 DROP TABLE 关键字删除 pets 表格。

Tips:
在终端输入指令时,按下键盘的向上和向下按钮,可以浏览之前输入的指令记录,这对于一些反复使用的指令非常有用;另外,在上一条指令输入有误时,也可以按下向上按钮,快速呼出指令直接进行修改。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容