在Android中一共提供了5种数据存储方式,分别为:

  (1)Files:通过FileInputStream和FileOutputStream对文件进行操作。具体使用方法可以参阅博文《Android学习笔记34:使用文件存储数据》。

  (2)Shared Preferences:常用来存储键值对形式的数据,对系统配置信息进行保存。具体使用方法可以参阅博文《Android学习笔记35:使用Shared Preferences方式存储数据》。

  (3)Content Providers:数据共享,用于应用程序之间数据的访问。

  (4)SQLite:Android自带的轻量级关系型数据库,支持SQL语言,用来存储大量的数据,并且能够对数据进行使用、更新、维护等操作。

  (5)Network:通过网络来存储和获取数据。

  本篇博文介绍第四种方式,通过Android自带的SQLite数据库存储数据。

1.SQLite简介

  SQLite是一款开源的、嵌入式关系型数据库,第一个版本Alpha发布于2000年。SQLite在便携性、易用性、紧凑性、高效性和可靠性方面有着突出的表现。

  SQLite和C/S模式的数据库软件不同,它是一款嵌入式数据库,没有独立运行的进程,与所服务的应用程序在应用程序进程空间内共生共存。它的代码与应用程序代码也是在一起的,或者说嵌入其中,作为托管它的程序的一部分。因此不存在数据库的客户端和服务器,使用SQLite一般只需要带上它的一个动态库,就可以享受它的全部功能。

  数据库服务器在程序中的好处是不需要网络配置或管理。将数据库客户端与服务器运行在同一个进程中,可以省去不少的操作及麻烦:不用担心防火墙或者地址解析;不用浪费时间管理复杂的授权和权限;可以减少网络调用相关的消耗;可以简化数据库管理并使程序更容易部署。

  SQLite数据库通过数据库级上的独占性和共享锁来实现独立事务处理。这意味着多个进程可以在同一时间从同一数据库读取数据,但是只有一个可以写入数据。在某个进程向数据库执行写操作之前,必须获得独占锁定。在发出独占锁定后,其他的读写操作将不会再发生。

  此外,SQLite数据库中的所有信息(比如表、视图、触发器等)都包含在一个文件内,方便管理和维护。SQLite数据库还支持大部分操作系统,除电脑上使用的操作系统之外,很多手机上使用的操作系统同样可以运行。同时,SQLite数据库还提供了多语言的编程接口,供开发者使用。

2.SQL基本命令

  SQL是与关系型数据库通信的唯一方式。它专注于信息处理,是为构建、读取、写入、排序、过滤、映射、分组、聚集和通常的管理信息而设计的声明式语言。

  在讲解SQL基本命令之前,有必要先了解一下SQLite所支持的数据类型都有哪些。

2.1 SQLite支持的数据类型

  SQLite采用动态数据存储类型,会根据存入的值自动进行判断。SQLite支持以下5种数据类型:

  (1)NULL:空值

  (2)INTEGER:带符号的整型

  (3)REAL:浮点型

  (4)TEXT:字符串文本

  (5)BLOB:二进制对象

2.2 SQL基本命令

  表是探索SQLite中SQL的起点,也是关系型数据库中信息的标准单位,所有的操作都是以表为中心的。那么如何使用SQL命令创建一张表呢?

2.2.1创建表

  表是由行和列组成的,列称为字段,行称为记录。

  使用CREATE命令可以创建表,CREATE命令的一般格式为:

  CREATE [TEMP/TEMPORARY] TABLE table_name (column_definitions [, constraints]);

  其中,[]中的内容是可选的,用TEMP或TEMPORARY关键字声明的表是临时表,这种表只存活于当前会话,一旦连接断开,就会被自动销毁。如果没有明确指出创建的表是临时表,则创建的是基本表,将会在数据库中持久存在,这也是数据库中最常见的表。

  CREATE TABLE命令至少需要一个表名和一个字段名,上述命令中的table_name表示表名,表名必须与其他标识符不同。column_definitions由用逗号分隔的字段列表组成,每个字段定义包括一个名称、一个域(类型)和一个逗号分隔的字段约束。其中,域是指存储在该列的信息的类型,约束用来控制什么样的值可以存储在表中或特定的字段中。

  一条创建表的命令示例如下:

1   CREATE TABLE tab_student (studentId INTEGER PRIMARY KEY AUTOINCREMENT,
2   studentName VARCHAR(20),
3   studentAge INTEGER);

  如上,我们创建了一个名为tab_student的表,该表包含3个字段:studentId、 studentName和studentAge,其数据类型分别为:INTEGER、VARCHAR和INTEGER。

  此外,通过使用关键字PRIMARY KEY,我们指定了字段studentId所在的列是主键。主键确保了每一行记录在某种方式上与表中的其他行记录是不同的(唯一的),进而确保了表中的所有字段都是可寻址的。

  SQLite为主键提供自增长功能,当定义字段类型为INTEGER PRIMARY KEY时,SQLite将为该字段创建默认值,该默认值确保整数值是唯一的。SQLite使用64-bit单符号整数主键,因此,该字段的最大值是9,223,372,036,854,775,807。当达到最大值时,SQLite会自动搜索该字段还未使用的值,并作为要插入的值。从表中删除记录时,rowid可能被回收并在后面的插入中使用。因此,新创建的rowid不一定是按照严格顺序增长的。如果想要SQLite使用唯一的自动主键值,而不是填补空白,可以在主键定义INTEGER PRIMARY KEY中加入关键字AUTOINCREMENT。AUTOINCREMENT关键字阻止rowid回收,它将为新插入的记录产生新的(不是回收的)rowid。

2.2.2插入记录

  使用INSERT命令可以一次插入一条记录,INSERT命令的一般格式为:

  INSERT INTO tab_name (column_list) VALUES (value_list);

  其中,tab_name指明将数据插入到哪个表中,column_list是用逗号分隔的字段名称,这些字段必须是表中存在的,value_list是用逗号分隔的值列表,这些值是与column_list中的字段一一对应的。

  比如,向刚才创建的tab_student表中插入一条记录,便可以使用如下的语句完成:

  INSERT INTO tab_student (studentId, studentName, studentAge) VALUES (1, “jack”, 23);

  通过以上的语句,便插入了一条studentName=”jack”, studentAge=”23”的记录,该记录的主键为studentId=1。

2.2.3更新记录

  使用UPDATE命令可以更新表中的记录,该命令可以修改一个表中一行或者多行中的一个或多个字段。UPDATE命令的一般格式为:

  UPDATE tab_name SET update_list WHERE predicate;

  其中,update_list是一个或多个字段赋值的列表,字段赋值的格式为column_name=value。WHERE子句使用断言识别要修改的行,然后将更新列应用到这些行。

  比如,要更新刚才插入到tab_student表中的记录,便可以使用如下的语句完成:

  UPDATE tab_student SET studentName=”tom”, studentAge=”25” WHERE studentId=1;

  通过以上的语句,便可以将刚才插入的主键为studentId=1的记录更新为studentName=”tom”, studentAge=”25”了。

2.2.4删除记录

  使用DELETE命令可以删除表中的记录,DELETE命令的一般格式为:

  DELETE FROM table_name WHERE predicate;

  其中,table_name指明所要删除的记录位于哪个表中。和UPDATE命令一样,WHERE子句使用断言识别要删除的行。

  比如,要删除刚才插入的记录,便可以使用如下的语句完成:

  
  DELETE FROM tab_student WHERE studentId=1;

2.2.5查询记录

  SELECT命令是查询数据库的唯一命令。SELECT命令也是SQL命令中最大、最复杂的命令。

  SELECT命令的通用形式如下:

  SELECT [distinct] heading 

  FROM tables 

  WHERE predicate 

  GROUP BY columns 

  HAVING predicate 

  ORDER BY columns 

  LIMIT count,offset;

  其中,每个关键字(如FROM、WHERE、HAVING等)都是一个单独的子句,每个子句由关键字和跟随的参数构成。GROUP BY和HAVING一起工作可以对GROUP BY进行约束。ORDER BY使记录集在返回之前按一个或多个字段的值进行排序,可以指定排序方式为ASC(默认的升序)或DESC(降序)。此外,还可以使用LIMIT限定结果集的大小和范围,count指定返回记录的最大数量,offset指定偏移的记录数。

  在上述的SELECT命令通用形式中,除了SELECT之外,所有的子句都是可选的。目前最常用的SELECT命令由三个子句组成:SELECT、FROM、WHERE,其基本语法形式如下:

  SELECT heading FROM tables WHERE predicate;

  比如,要查询刚才插入的记录,便可以使用如下的语句完成:

  
  SELECT studentId, studentName, studentAge FROM tab_student WHERE studentId=1;

  至此,我们介绍了SQL中最基本和最常用的CREATE、INSERT、UPDATE、DELETE和SELECT命令。当然了,这里只是对其进行了简单的介绍,有关SQLite中SQL命令的详细使用方法,可以参阅《SQLite权威指南》一书的第三章和第四章。

3.数据库操作辅助类SQLiteOpenHelper

  Android提供了一个重要的类SQLiteOpenHelper,用于辅助用户对SQLite数据库进行操作。

  SQLiteOpenHelper的构造函数原型如下:

  public SQLiteOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version);

  其中,参数context表示应用程序运行的环境,包含应用程序所需的共享资源。参数name表示Android的数据库名字。参数factory是SQLiteDatabase.CursorFactory类对象,用于存储查询Android SQLite数据库的结果集。参数version表示应用程序所用的数据库的版本,该版本并非SQLite的真正版本,而是指定应用程序中的SQLite数据库的版本,当该版本号发生变化时,将会触发SQLiteOpenHelper类中的onUpgrade()或onDowngrade()方法。

  SQLiteOpenHelper类的所有方法如图1所示。

图1 SQLiteOpenHelper类的方法

  其中,close()方法用于关闭SQLiteOpenHelper对象中的SQLite数据库;getReadableDatabase()方法和getWriteableDatabase()方法类似,getReadableDatabase()方法以只读状态打开SQLiteOpenHelper对象中指定的SQLite数据库,任何想要修改数据库的操作都是不允许的;getWriteableDatabase()方法也是打开数据库,但是允许数据库正常的读/写操作;在一个不存在的数据库上调用任何方法时,都会隐式的调用SQLiteOpenHelper对象的onCreate()方法;当应用程序第一次访问数据库时,则会调用onOpen()方法,但是,如果版本号发生了变化的话,则会调用onUpgrade()或onDowngrade()方法。

4.数据库类SQLiteDatabase

  SQLiteDatabase类用来完成对数据库的操作任务,比如表的选择、插入、更新和删除语句等。

  SQLiteDatabase类中常用的用于执行SQL语句的方法有以下一些。

  (1)execSQL()方法:

  public void execSQL (String sql);

  public void execSQL (String sql, Object[] bindArgs);

  (2)query()方法:

  public Cursor query (String table, String[] columns, String selection, String[] selectionArgs, String  groupBy, String  having,String orderBy, String limit);

  public Cursor query (boolean distinct, String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit, CancellationSignal cancellationSignal);

  public Cursor query (String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String  having,String orderBy);

  public Cursor query (boolean distinct, String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit);

  (3)queryWithFactory()方法:

  public Cursor queryWithFactory (SQLiteDatabase.CursorFactory cursorFactory, boolean distinct, String table, String[]columns, String selection, String[] selectionArgs, String groupBy, String having, String  orderBy, String  limit,CancellationSignal cancellationSignal);

  public Cursor queryWithFactory (SQLiteDatabase.CursorFactory cursorFactory, boolean distinct, String table, String[]columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit);

  (4)rawQuery()方法:

  public Cursor rawQuery (String sql, String[] selectionArgs, CancellationSignal cancellationSignal);

  public Cursor rawQuery (String sql, String[] selectionArgs);

  (5)rawQueryWithFactory()方法:

  public Cursor rawQueryWithFactory (SQLiteDatabase.CursorFactory cursorFactory, String sql, String[]  selectionArgs,String editTable);

  public Cursor rawQueryWithFactory (SQLiteDatabase.CursorFactory cursorFactory, String sql, String[]  selectionArgs,String editTable, CancellationSignal cancellationSignal);

  其中,execSQL()方法都有一个参数sql,这个参数是一个SQL语句。第二个参数bindArgs接收一个数组,数组中的每个成员捆绑了一个查询。execSQL()方法用于运行那些没有返回值的查询语句,比如创建、插入、更新和修改表。

  query()方法和queryWithFactory()方法是在数据库中运行一些轻量级的单查询语句,参数包括table、columns、groupBy、having、orderBy、limit等SQL语句关键字。这些方法允许将SQL语句传递给相关方法,而不必直接使用SQL语句。

  rawQuery()方法和rawQueryWithFactory()方法也都有一个参数sql,用于执行SQL查询语句,返回值是Cursor对象。这两个方法都有一个版本能够接收一个字符串数组selectionArgs作为参数,通过这个参数,SQLiteDatabase对象将把捆绑的SQL语句中的问号(?)用这个数组中的值代替,并按照一一对应的位置关系进行取代。

  SQLiteDatabase类提供了大约50个方法,除此之外还有一些用于打开数据库的方法(如openDatabase()、openOrCreateDatabase()等),用于管理SQLite事务的方法(如beginTransaction()、endTransaction()等),用于测试数据库是否被锁住的方法(如isDbLockedByCurrentThread()、isDbLockedByOtherThread()等),以及获取数据库基本信息的方法(如getMaximumSiza()、getVersion()等)。这里就不一一介绍了,具体可以参阅SQLiteDatabase类的API帮助文档

5.游标类Cursor

  在Android中,查询数据是通过Cursor类来实现的,当我们使用SQLiteDatabase.query()或SQLiteDatabase.rawQuery()方法时,会得到一个Cursor对象,Cursor指向的就是每一条记录,它提供了很多有关查询的方法,如图2所示。

图2 Cursor类的常用方法

6.封装接口

  有了以上的基础,我们便可以按照MVC的架构,封装一个接口层,在该接口层中实现对SQLite数据库的具体操作。

  以下分别以添加数据、更新数据、查询数据为例讲解其具体的实现方法。在实现这些方法之前,我们首先需要创建一张表。这里我创建了一个名为MySQLiteOpenHelper的类,让它继承自SQLiteOpenHelper类,并实现了SQLiteOpenHelper类的onCreate()方法,在该方法里实现创建一张表的操作,具体源代码如下:

1     /*
2 * Function : 创建表
3 * Author : 博客园-依旧淡然
4 */
5 public void onCreate(SQLiteDatabase db) {
6 db.execSQL("CREATE TABLE tab_student (studentId INTEGER PRIMARY KEY AUTOINCREMENT, " +
"studentName VARCHER(20), " +
"studentAge INTEGER)");
7 }

  通过以上的代码,我们创建了一张名为“tab_student”的表,并在该表中创建了三个字段,分别为:studentId、studentName和studentAge。并且指定了studentId字段作为该表的主键。

6.1添加数据

  添加数据可以使用SQLiteDatabase.execSQL(String sql, Object[] bindArgs)方法来实现,具体如下:

1     /*
2 * Function : 添加数据
3 * Author : 博客园-依旧淡然
4 */
5 public void addStudentInfo(Student student) {
6 db = mySQLiteOpenHelper.getWritableDatabase();
7 db.execSQL("INSERT INTO tab_student (studentId, studentName, studentAge) values (?, ?, ?)",
8   new Object[] {student.getStudentId(), student.getStudentName(), student.getStudentAge()});
9 }

  其中,通过第二个参数bindArgs,使SQL语句中的问号(?)与这个数组中的值形成一一对应关系,从而将值写入到“tab_student”表中的对应字段中。

6.2更新数据

  更新数据的方法与添加数据的方法大致相同,具体如下:

1    /*
2 * Function : 更新数据
3 * Author : 博客园-依旧淡然
4 */
5 public void updateStudentInfo(Student student) {
6 db = mySQLiteOpenHelper.getWritableDatabase();
7 db.execSQL("UPDATE tab_student SET studentName = ?, studentAge = ? WHERE studentId = ?",
  new Object[] {student.getStudentName(), student.getStudentAge(), student.getStudentId()});
8 }

6.3查询数据

  查询数据时,因为需要返回查询的结果,所以需要使用SQLiteDatabase.rawQuery()方法将查询的结果返回,具体如下:

 1     /*
2 * Function : 查询数据
3 * Author : 博客园-依旧淡然
4 */
5 public Student findStudentInfo(int id) {
6 db = mySQLiteOpenHelper.getWritableDatabase();
7 String sql = "SELECT studentId, studentName, studentAge FROM tab_student WHERE studentId = ?";
8 Cursor cursor = db.rawQuery(sql, new String[] {String.valueOf(id)});
9 if(cursor.moveToNext()) {
10 return new Student(cursor.getInt(cursor.getColumnIndex("studentId")),
cursor.getString(cursor.getColumnIndex("studentName")),
11 cursor.getInt(cursor.getColumnIndex("studentAge")));
12 }
13 return null;
14 }

  可以看出,通过使用SQLiteDatabase.rawQuery()方法可以将查询到的结果存入Cursor对象中。然后,我们可以使用Cursor对象的getXXX()方法将查询结果从Cursor对象中取出来。

  当然了,我们还可以根据实际的需要,去实现更多的接口方法,比如,删除数据、获取数据列表、获取数据个数等等。

  封装好了以上的这些接口方法,便可以很方便的在程序中直接调用这些方法,不必再去关心底层数据库的调用,而将精力放在UI界面的设计实现上。

Android学习笔记36:使用SQLite方式存储数据的更多相关文章

  1. android学习笔记36——使用原始XML文件

    XML文件 android中使用XML文件,需要开发者手动创建res/xml文件夹. 实例如下: book.xml==> <?xml version="1.0" enc ...

  2. Android 学习笔记之Volley(七)实现Json数据加载和解析...

    学习内容: 1.使用Volley实现异步加载Json数据...   Volley的第二大请求就是通过发送请求异步实现Json数据信息的加载,加载Json数据有两种方式,一种是通过获取Json对象,然后 ...

  3. Android学习之Http使用Post方式进行数据提交(普通数据和Json数据)

    转自:http://blog.csdn.net/wulianghuan/article/details/8626551 我们知道通过Get方式提交的数据是作为Url地址的一部分进行提交,而且对字节数的 ...

  4. Android学习笔记(36):Android的两种事件处理方式

    Android提供了两种事件处理的方式:基于回调的事件处理 和 基于监听的事件处理. 我们来说的easy理解一点: (1)基于回调的事件处理就是继承GUI组件,并重写该组件的事件处理方法.除了一些特定 ...

  5. Android学习笔记④——页面的布局方式

    FrameLayout(帧布局) 这个布局的特点是简单的默认把每一个视图组件都放在边框内且放在左上角,即使添加多个视图组件,他们也都是重叠在左上角,新的视图会遮挡住旧的视图.可以根据gravity来改 ...

  6. Android学习笔记--通过wifi向服务器端发送数据

    (转自http://www.cnblogs.com/zhxiang/archive/2011/07/21/2112825.html) 客户端程序: 1 2 3 4 5 6 7 8 9 10 11 12 ...

  7. (转)Android学习笔记---SQLite介绍,以及使用Sqlite,进行数据库的创建,完成数据添删改查的理解

    原文:http://blog.csdn.net/lidew521/article/details/8655229 1.SQLite介绍:最大特点是,无数据类型;除了可以使用文件或SharedPrefe ...

  8. 【转】 Pro Android学习笔记(三五):Menu(6):XML方式 & PopUp菜单

    目录(?)[-] 利用XML创建菜单 XML的有关属性 onClick事件 Pop-up菜单 利用XML创建菜单 在代码中对每个菜单项进行设置,繁琐且修改不灵活,不能适配多国语言的要求,可以利用资源进 ...

  9. Android提供了5种方式存储数据:

    --使用SharedPreferences存储数据: --文件存储数据: --SQLite数据库存储数据: --使用ContentProvider存储数据: --网络存储数据: 一:使用SharedP ...

随机推荐

  1. FLV视频播放:对未缓冲进度条实现拖动

    FLV视频播放:对未缓冲进度条实现拖动  流媒体开发 Add comments 八282010 一.文件准备 1.转码:ffmpeg 2.添加元数据:yamdi 二.网页播放器:jw player 使 ...

  2. Android + Eclipse + PhoneGap 3.4 安卓最新环境配置,部分资料整合网上资料,已成功安装.

    前言:广州花都论坛,打算推出本地服务o2o应用.快速开发手机应用,phonegap 我的小站,http://www.w30.cn/ 如果有什么问题也可以到小组留言,可以的话,贡献一个ip:) phon ...

  3. Tetris

    he Tetris game is one of the most popular computer games ever created. The original game was designe ...

  4. Linux mkdir 如何递归创建目录?

    mkdir 如何递归创建目录? mkdir –vp 目录1/目录2/目录3   详细介绍: linux mkdir 命令用来创建指定的名称的目录,要求创建目录的用户在当前目录中具有写权限,并且指定的目 ...

  5. sqlserver2008 R2中查找未使用过的索引

    转自:http://blog.csdn.net/yangzhawen/article/details/7247393 sqlserver2008 R2中查找未使用过的索引: o.name AS 表名 ...

  6. jQuery特性

      CreateTime--2017年7月17日11:45:27Author:Marydon jQuery特性 1.jQuery取值 使用jQuery进行页面取值时,获取到的值的类型有两种:strin ...

  7. 【BIRT】Format Number下的Round Mode中的各项解释

    页面展示 从上图我们可以才看出,共有Half Up.Half Down.Half Even.Up.Down.Celling.Floor.Unnecessary 下面一一介绍每一个的意思 Half Up ...

  8. jquery获取json对象中的key小技巧,遍历json串所有key,value

    比如有一个json var json = {"name" : "Tom", "age" : 18}; 想分别获取它的key 和 value ...

  9. 2、JSP脚本

    JSP脚本 JSP脚本包含了JSP表达式.声明标识和脚本程序.通过这些标识,在JSP页面中可以如同编写Java程序一样来声明变量.定义方法和执行各种表达式的运算 1.在JSP中应用代码片段 语法格式: ...

  10. 一招破解混淆后的JavaScript代码

    http://www.cnblogs.com/zjyuan/archive/2011/12/14/2287647.html JavaScript不是很给力,想怎么破解就怎么破解!此文章教你的不仅仅是破 ...