SQLite基础学习总结

Android中的存储问题,是每个Android开发者都需要面对的一个问题,而且,数据存储应该是一个关键,网上很多说Android有五大存储方式,其中包括SharedPreference、File、Content Provider、SQLite数据库存储和网络存储,不过看API指南中的数据存储并没有包括Content Provider,而且按文档所说的,严格意义上来讲,Content Provider只是用于管理应用的数据访问权限的,是Android的组件之一。当然这不是本文的重点,重点是,Android的存储方式中包括了SQLite数据库存储,所以在学习了SQLite的相关内容之后,记下我认为有必要的内容作为总结,其他的语法语句都可以在网上搜到。

SQlite是什么

简单来讲,SQLite是一款数据库,可以帮助用户存储和管理一些数据。它是用C语言实现的一个开源的嵌入式的关系数据库管理系统。所谓嵌入式,就是说SQLite嵌入到应用程序中,不需要再去进行服务器的配置就可以使用。Android在运行时也集成了SQLite,每个Android的应用程序都可以使用SQLite数据库来管理数据,如果Android应用有用到SQLite数据库的话,可以在路径data/data/{packagename}/下找到。

SQLite是一款轻量级的数据库,清到不需要一个单独的服务器进程或操作系统,清到在完全配置时容量小于400kb,但是SQLite功能也很完善,基本能满足普通的需求,支持SQL92标准的大多数查询语言的功能,而且能跨平台运行。当然SQLite也有一定的局限性,对于网络数据存储、大数据量以及并发操作还是需要服务器数据库来助力的。

安装SQLite

由于SQLite是零配置的,所以安装过程相当简单,甚至在Linux和Mac中一般都会默认是预装的,可以通过终端输入sqlite3进行验证,如果没有的话,和Windows一样,到官网下载页面下载相对应的文件进行操作,Windows的话最好配置下Path环境变量,方便日后操作调用。最终通过验证指令就可以看到SQLite 的版本信息了。

SQLite的命令和语法

操作SQLite的指令有两种,一种是SQLite命令,另一种是SQLite语法。SQLite命令又称为点命令,一般来讲以.开头(也有像sqlite3这种例外的命令),而且不以分号(;)结束,用于对数据库系统(即SQLite程序)进行管理设置;SQLite语法每一句都以分号(;)结束,是对数据库文件的一种操作。SQLite语法根据操作性质可以分为以下几种:

DDL-数据定义语言:包括CREATE(创建一个新的表,一个表的视图,或者数据库中的其他对象)、ALTER(修改数据库中的某个已有的数据库对象,比如一个表)、DROP(删除整个表,或者表的视图,或者数据库中的其他对象,不能删除数据库)

DML-数据操作语言:包括INSERT(创建一条记录)、UPDATE(修改记录)、DELETE(删除记录)

DQL-数据查询语言:SELECT(从一个或多个表中检索某些记录)

记录是指插入到数据库中的值
另:SQLite对于大小写不敏感,除了特殊指令GLOB外,其他不区分大小写,但是语句一般都会大写

SQLite存储数据的形式和数据类型

SQLite中存储数据的形式有点类似于EXCEL,在EXCEL中每一个xls文件里都包含有多个sheet表,而在SQLite中,则是databasetable的概念,database就相当于xls文件,而table则相当于sheet表。

每一个table也是以表格的形式来展示数据的,以列为基准,每新增一组数据就增加一行。在数据库中,每一列中的数据称为一个字段,每一行称为一条记录。原则上讲,在创建table时第一条记录的字段会定义它所处的一列中字段的属性,如数据类型等,也就是说,table中的每一列的数据类型都应该是相同的。但是由于SQLite的数据类型是弱类型,可以在某一列中插入数据类型不同于其他记录值的记录值。比如创建时定义第一列为INTEGER类型,当你往第一列插入记录时,如果不是INTEGER类型的数据,SQLite会尝试将其转换为INTEGER类型,如果转换失败,会直接将这个数据以其原本的类型插入到第一列。也就是说,可以在定义为整数型的列中插入字符类型的数据,并且它的类型不被强制改变。如下图中第三行中的数据就与同列其他数据的类型不相同:

different-type

SQLite基本操作

SQLite在Android应用的中操作基本就是增删改查四类。在此之前需要创建数据库和表。

创建数据库

SQLite中的sqlite3命令用来打开或创建新的数据库。其基本语法如下:

$sqlite3 DatabaseName.db

如果DatabaseName.db文件存在则直接打开,不存在则新建并打开。.db后缀可以不加,但为了识别方便,一般都会加上。

示例如下,创建一个新的数据库testDB.db

1
2
3
4
$sqlite3 testDB.db
SQLite version 3.15.1 2016-11-04 12:08:49
Enter ".help" for usage hints.
sqlite>

每执行完一句指令都会在最后出现一个sqlite>提示符,创建完之后可以使用.databases来查询现有的数据库:

databases

退出SQLite程序的指令为.quit

创建表

创建表的语句为CREATE TABLE,其基本语法如下:

1
2
3
4
5
6
CREATE TABLE database_name.table_name(
column1 datatype PRIMARY KEY AUTOINCREMENT,
column2 datatype,
column3 datatype,
......
columnN datatype);

database_name.table_name中的database_name可省略,table_name是表的唯一标识
column1、column2等这些是第一条记录中字段的名称,可以简单理解为表头,一般大写。SQLite指令对大小写不敏感,但是插入到表中的值会保持和输入的状态一致
datatype是指该列的数据类型,一般大写
PRIMARY KEY指出这一列是表的主键,是用来唯一标识表中记录的关键,一旦指出了PRIMARY KEY,就说明这一列当中的记录具有唯一性,不能重复,可以根据主键定位到具体的行,在Android应用中一般指_id,与AUTOINCREMENT结合使用
AUTOINCREMENT是自增长的意思,即使不设置值也会对上一行的值自动增加1,这个约束只对整数型有效

示例如下,创建一个表COMPANY,增加五列_id、NAME、AGE、ADDRESS、SALARY:

1
2
3
4
5
6
7
sqlite> CREATE TABLE COMPANY(
...> _id INTEGER PRIMARY KEY AUTOINCREMENT,
...> NAME TEXT,
...> AGE INTEGER,
...> ADDRESS TEXT,
...> SALARY REAL);
sqlite>

创建完成可以用.tables命令查询数据库中的表:

tables

在dos或终端的界面可以用.schema命令得到表的完整信息,输出的是建表时输入的语句

增-INSERT语句

INSERT顾名思义就是往表中添加数据行,其基本语法如下:

1
2
INSERT INTO table_name (column1, column2, ..., columnN)
VALUES (value1, value2, ..., valueN);

column指的是列的名称,可以省略
value指的是需要插入到表中的数据,与列出的column一一对应,当column省略时,value需要与完整的列名一一对应

示例如下,往表中添加记录:

1
2
3
sqlite> INSERT INTO COMPANY(_id, NAME, AGE, ADDRESS, SALARY)
...> VALUES (1, 'Paul', 32, 'California', 20000);
sqlite>

也可以省略column:

1
2
sqlite> INSERT INTO COMPANY VALUES (2, 'Allen', 25, 'Texas', 15000);
sqlite>

或者省略自增长的主键_id:

1
2
3
sqlite> INSERT INTO COMPANY (NAME, AGE, ADDRESS, SALARY)
...> VALUES ('Teddy', 23, 'Norway', 20000);
sqlite>

最终结果如下:

table-company

可以看到,每一行的数据都完整的记录到表中了,显示表中记录的语句就是

查-SELECT语句

SELECT语句可以查询并列出表中的记录值,其基本语法如下:

1
SELECT column1, column2, columnN FROM table_name;

其中多个column可以用*代替表示查询所有列

示例查询表中第一列:

select

现在默认的输出格式是list,对于阅读不是很友好,可以使用.mode.headers来格式化输出:

.mode column可以设置为按列输出:

mode-column

.headers on可以设置显示表头,off则不显示表头,在设置了mode的基础上设置:

headers-on

SELECT语句可以与WHERE子句一起用来进行更小范围的查询,WHERE指明了查找范围,如查找_id为3的行的相关记录:

select-where

改-UPDATE语句

UPDATE用来修改表中的记录,看名字也知道是更新。基本语法如下:

1
2
3
UPDATE table_name
SET column1 = value1, column2 = value2, ...., columnN = valueN
WHERE [condition];

示例如下,更新_id为2的AGE:

update

删-DELETE语句

DELETE用来删除整行记录,其基本语法如下:

1
2
DELETE FROM table_name
WHERE [condition];

示例如下,删除_id为2的记录:

delete

如果不指定WHERE子句,则表示清空表中所有记录,但是表依然存在,还有一个DROP语句可以删除表:DROP TABLE table_name

补充内容

基本的增删改查如上所述,但是有时候一张表不能满足需求,会产生多张表甚至多个数据库,这时候就需要多重操作了。

多数据库操作

有时候会有很多个数据库,按照常规步骤,想要对另外一个数据库进行操作,先要quit出当前的数据库再重新进入下一个数据库,这样就挺麻烦的,而且有时候会需要从这个数据库中备份数据放到另一个数据库,常规的步骤实现就麻烦了,这时SQLite给我们提供了附加数据库这一功能,也就是ATTACH DATABASE

附加数据库可以支持我们在当前的数据库中对另外的数据库进行操作,只需要给需要附加操作的数据库添加一个别名就行了,基本语法如下:

1
ATTACH DATABASE 'Database2' As 'Alias-Name';

要注意其中的符号不能少,Database2只需要附加进来进行操作的数据库,Alias-Name是它在当前环境下的名称,即别名。示例如下:

attach

当我使用了ATTACH语句时,会将Database2也就是图中的testDB.db以别名tst在当前界面被操作。如果Database2在ATTAHCH之前不存在则会新建一个数据库并命名为Database2。这时查看当前的数据库会发现有两个,一个是之前的testDB.db,一个是testDB2.db。现在就可以同时对两个数据库进行操作了,如果是对当前数据库操作的话和平常一样,如果是对附加进来的testDB2.db进行操作则需要加上数据库名称,就是指定的别名tst。

示例如下,在当前数据库下对testDB2.db新建一个表并命名为TEST_TABLE,在这里需要指定表名为tst.TEST_TABLE:

attach-create

不加上数据库名同样可以创建表TEST_TABLE:

create-2

这时查询发现创建的三个表都在,现在我们把数据库分离,使用DETACH DATABASE语句,其基本语法如下:

1
DETACH DATABASE 'Alias-Name';

来试一下分离testDB2.db,注意只能使用别名,而且当前数据库及别名为main的不能分离:

deatch

分离之后就只剩下当前的testDB.db这个数据库了,再查看表的时候,tst.TEST_TABLE并不在其中,这时我们quit一下,再进入到testDB2.db中看看有没有表:

check-table

现在就明白了,当进行了ATTACH操作之后,凡是以别名操作的都不会影响主要数据库,除非你ATTACH的是自己本身。

多表操作(INNER JOIN)

多表是比较常见的,在Android开发中,有时候需要多个表来对数据进行更精确的分类存储。一般用到的就是Joins子句,可以对多个表的记录进行整合,这是主键作用就大了。这个操作一般称为JOIN,JOIN有三种类型,CROSS JOIN(交叉连接)、INNER JOIN(内连接)和OUTER JOIN(外连接)。

JOIN会把第一个表的每一行与第二个表的每一行进行匹配组合成一个新表,所以如果第一个表有x列a行,第二个表有y列b行,JOIN出来的表就有x+y列,行数会根据JOIN的类型不同而不同,最常用的是INNER JOIN,这里直说这个,其他两个可以前往这个链接了解。

INNER JOIN的基本语法如下:

1
SELECT ... FROM table1 [INNER] JOIN table2 ON conditional_expression ...

conditional_expression可以指定条件,一般是指定两个表两个列的记录相等,从而得到相应完整的表。示例如下:

新建一个表DEPARTMENT并插入记录,完善表COMPANY,最终两个表记录如下:

datas

现在执行内链接:

1
2
sqlite> SELECT EMP_ID, NAME, DEPT FROM COMPANY INNER JOIN DEPARTMENT
ON COMPANY._id = DEPARTMENT.EMP_ID;

可以看到,通过将COMPANY中的_id与DEPARTMENT中的EMP_ID相对应,完成了两个表的整合,得到了一份更完整的信息。

数据库注入问题

数据库注入是在允许用户将输入的内容插入表中的情况下,用户有可能插入危险性的SQLite语句来对数据库进行破坏的一个安全问题。假设允许用户输入自己的姓名name,用户除了输入name之外,还有可能输入一些语句,如:

1
name = 'myname; DROP TABLE table_name;'

在这种情况下,一旦用户输入插入到表中,同时就注入了一条DROP语句,会删除整张数据库表。所以在应用中需要对用户的输入进行限制。具体就不在这里再谈了,不同的应用环境都不太一样~

总结

以上就是学习SQLite之后的一些总结了,更详细的教程网上一搜一大堆,都是一些基本语句操作,不是很难,完全掌握还需要日常多运用。

本文到此就结束了,如果有大神路过发现有不妥的地方烦请指正~


文章属原创,欢迎转载,但请务必保留原文链接!

呼啦啦...