前面一讲介绍了数据持久化技术的前两种:文件存储、SharedPreferences存储。下面介绍第三种技术:SQLite数据库存储
一、SQLite数据库存储
SQLite数据库是一款轻量级的关系型数据库,它的运算速度非常快,占用资源很少,通常只需要几百KB的内存就足够了,因而特别适合在移动设备上使用。SQLite不仅支持标准的SQL语法,还遵循了数据库的ACID事务,所以只要你以前使用过其他的关系型数据库,就能很快上手。而SQLite又比一般的数据库要简单的得多,它甚至不用设置用户名和密码就可以使用。Android正是把这个功能极为强大的数据库嵌入到了系统当中,成为了Android系统的内置数据库,使得本地持久化的功能有了一次质的飞跃。
前面我们所学的文件存储和SharedPreferences存储毕竟只适用于保存一些简单的数据和键值对,当需要存储大量复杂的关系型数据的时候,这两种存储方式就很难应付了,这时候就需要使用到SQLite数据库。
1.1、创建数据库(SQLiteOpenHelper帮助类)
Android为了让我们更加方便地管理数据库,专门提供了一个SQLiteOpenHelper帮助类,借助这个类我们可以非常简单的对数据库进行创建和升级。下面就来介绍一下SQLiteOpenHelper的基本用法。
1、首先需要知道SQLiteOpenHelper是一个抽象类,这意味着如果我们想要使用它的话,就需要创建一个自己的帮助类去继承它,SQLiteOpenHelper中有两个抽象方法,分别是:onCreate()方法和 onUpgrade()方法,我们必须在自己的帮助类中重写这两个方法,然后分别在这两个方法中去实现创建、升级数据库的逻辑。
2、SQLiteOpenHelper中还有两个非常重要的实例方法:getReadableDatabase()和getWritableDatabase()。这两个方法都可以创建或打开一个现有的数据库(如果数据库已经存在则直接打开,否则创建一个新的数据库),并返回一个对数据库进行读写操作的对象,不同的是,当数据库不可写入的时候(如磁盘空间已满),getReadableDatabase()方法返回的对象将以只读的方式去打开数据库,而getWritableDatabase()方法则将出现异常。
3、SQLiteOpenHelper中有两个构造方法可供重写,一般使用参数少一点的那个构造方法即可。这个构造方法中接收4个参数,第一个参数是Context,这个没什么好说的,必须要有它才能对数据库进行操作;第二个参数是数据库名,创建数据库时使用的就是这里指定的名称;第三个参数允许我们在查询数据的时候返回一个自定义的Cursor,一般都是传入null;第四个参数表示当前数据库的版本号,可用于对数据库进行升级操作。构建出SQLiteOpenHelper的实例后,再调用它的:getReadableDatabase()或getWritableDatabase()方法就能创建数据库了,数据库文件会存放在:/data/data/程序包名/databases/目录下。此时,重写的onCreate()方法也会得到执行,所以通常会在这里去处理一些创建表的逻辑。
接下来我们就通过实际的例子来直观的体会一下SQLiteOpenHelper的用法吧。
这里我们希望创建一个名为BookStore.db的数据库,然后在这个数据库中新建一张Book表,表中有id(主键)、作者、价格、页数和书名等列,创建数据库表当然还是需要用建表语句的,Book表的建表语句如下所示:
SQLite不像其他数据库拥有众多复杂的数据类型,它的数据类型很简单,integer表示整型,real表示浮点型,text表示文本类型,blob表示二进制类型。另外我们还使用了primary key将id设置为主键,并用autoincrement关键字表示id列是自增长的。
然后我们开始写代码:
第一步:新建MyDatabaseHelper类继承SQLiteOpenHelper
第二步:设置一个按钮,用于实现点击按钮创建数据库和建表的功能
第三步:在MainActivity中实现数据库和表的创建
第四步:运行程序,点击按钮,弹出一个创建成功的Toast提示,说明数据库和表我们都已经创建完成了。
数据库和表都创建完成后,我们知道它是保存在:/data/data/com.workspace.hh.databasetest/databases目录下,如果还是使用File Explorer打开,我们只会看到一个BookStore.db文件,看不到Book表,这里我们换一个打开方式来查看数据库和Book表,就是使用adb shell来对数据库和表的创建情况进行检测。
adb是Android SDK中自带的一个调试工具,使用这个工具可以直接对连接在电脑上的手机或模拟器进行调试操作,它存放在sdk的platform-tools目录下,如果想要在命令行中使用这个工具,就需要先把它的路径配置到环境变量中。打开计算机 ---> 属性 ---> 高级系统设置 ---> 环境变量,然后在系统变量中找到Path并点击编辑,将platform-tools目录配置进去,如图所示:
配置完成后,就可以使用adb工具了:
(1)打开Android Studio中的Terminal工具:
(2)输入:adb shell,回车,进入到设备的控制台
(3)使用cd命令进入到db文件的目录:
(4)使用:ls命令来查看该目录里的文件:该目录下出现了两个数据库文件,一个正是我们的创建的BookStore.db,而另外一个BookStore.db-journal则是为了让数据库能够支持事务而产生的临时日志文件,通常情况下这个文件的大小都是0字节。
(5)借助sqlite命令来打开数据库:sqlite3 BookStore.db
(6)打开数据库后,就可以对这个数据库中的表进行管理了,首先我们看一下数据库中有哪些表:(.table)
可以看到数据库中有两张表,android_metadata表示每个数据库中都会自动生成的,不用管它,而另外一张book表就是我们创建的了。
(7)通过(.schema)命令来查看它们的建表语句:从建表语句中我们可以看出,数据库和表已经创建完成了。
(8)通过(.exit)或(.quit)命令退出数据库的编辑,然后再通过(exit)命令退出设备的控制台
1.2、升级数据库
在上面MyDatabaseHelper中还保留了一个:onUpgrade()方法,这个方法就是用于对数据库进行升级的,它在整个数据库的管理工作中起着非常重要的作用。目前DatabaseTest项目中已经存在一张Book表用于存放书的各种详细数据,接着我们再添加一张Category表用于记录图书的分类,Category表中有id(主键)、分类名个分类代码这几列,建表语句如下:
现在我们开始在代码中进行建表:
第一步:修改MyDatabaseHelper中的代码:
第二步:要执行:onUpgrade()方法,只需要输入一个比当前数据库的版本号大的版本号就行了
第三步:运行程序,点击按钮,我们看到有Toast提示弹出,接着我们检查数据库中是否成功创建了Category表,发现建表成功。
1.3、添加数据
我们对数据库的操纵无非就4种:CRUD,即:Create添加、Retrieve查询、Update更新、Delete删除。每一种操作都各自对应了一种SQL命令:添加用insert、查询用select、更新用update、删除用delete;Android提供了一系列的辅助方法,使得在Android中即使不去编写SQL语句,也能轻松完成所有的CRUD操作。
前面我们已经知道,调用SQLiteOpenHelper的:getReadableDatabase()或getWritableDatabase()方法是可以用于创建和升级数据库的,不仅如此,这两个方法还都会返回一个SQLiteDatabase对象,借助这个对象我们就可以对数据进行CRUD操作了。
SQLiteDatabase中提供了一个:insert()方法,这个方法就是专门用于添加数据的,它接收3个参数,第一个参数是表名,向哪个表添加数据,就是传入哪个表的名字;第二个参数是用于在未指定添加数据的情况下给某些可为空的列自动赋值NULL,一般我们用不到这个功能,直接传入null即可;第三个参数是一个ContentValues对象,它提供一系列的:put()方法重载,用于向ContentValues中添加数据,只需要将表中的每个列名以及相应的待添加数据传入即可。
下面就提高例子来亲自体验一下添加数据的操作:
第一步:创建一个按钮,通过点击按钮来添加数据
第二步:在MainActivity中实现添加数据的操作:
第三步:运行程序,看到有添加数据成功的提示信息,然后通过:(select * from book;)查询语句查看添加的两条数据(注意查询语句后面有分号)
1.4、更新数据
SQLiteDatabase中也提供了一个非常好用的:update()方法,用于对数据进行更新,这个方法接收4个参数,第一个参数个insert()方法一样,也是表名,指定去更新哪张表里的数据。第二个参数是ContentValues对象,要把更新的数据在这里组装进去。第三、第四个参数用于约束更新某一行或某几行中的数据,不指定的话默认就是更新所有行。
第一步:创建一个按钮,通过点击按钮实现数据更新
第二步:在MainActivity中实现业务逻辑
第三步:运行程序,点击按钮,在Terminal中查看是否更新成功
1.5、删除数据
SQLiteDatabase中提供了一个:delete()方法,专门用于删除数据,这个方法接收三个参数,第一个参数仍然是表名,第二、三个参数又是用于约束删除某一行或几行的数据,不指定的话默认就是删除所有行。
第一步:添加一个删除按钮,通过点击按钮来删除数据
第二步:在MainActivity中实现功能
第三步:运行程序,点击按钮,然后查看book表中的数据是否被删除,从查询的数据中,我们可以看出,页数为899的“The mental of Java”这本书已经被删除。
1.6、查询数据
SQLite的全称是:Structured Query Language,翻译成中文就是结构化查询语言,它的大部分功能都体现在“查”这个字上,而“增删改”只是其中的一小部分功能。SQLiteDatabase中还提供了一个:query()方法用于对数据进行查询,这个方法的参数非常的复杂,最短的一个方法重载也需要传入7个参数,这7个参数的含义是:
第一个参数:表名,即我们希望在哪张表中查询数据
第二个参数:指定去哪儿查询哪几列,如果不指定则默认查询所有列
第三、四个参数:约束查询某一行或某几行的数据,不指定则默认查询所有行的数据
第五个参数:指定需要去group by的列,不指定则表示不对查询结果进行group by操作
第六个参数:对group by之后的数据进行进一步的过滤,不指定则表示不进行过滤
第七个参数:指定查询结果的排序方式,不指定则表示使用默认的排序方式。
具体的内容可参照下表:
虽然:query()方法的参数非常多,但是我们不必为每条查询语句都指定所有的参数,多数情况下只需要传入少数几个参数就可以完成查询操作了。调用query()方法后会返回一个Cursor对象,查询到的所有数据都将从这个对象中取出。接下来我们就通过一个简单的例子来体验数据的查询操作:
第一步:创建一个按钮,通过点击按钮来查询数据
第二步:在MainActivity中实现功能逻辑
第三步:打印出查询到数据
1.7、使用SQL操作数据库
Android提供了一系列方法可以直接通过SQL来操作数据库,上面的CRUD操作可以用下面的SQL语句来完成:
除了查询语句的时候调用的是SQLiteDatabase的:rawQuery()方法,其他操作都是调用:execSQL()方法。