为存储数据到数据库,首先需要定义数据库结构并打开数据库。 Android 提供了一个帮助类 SQLiteOpenHelper
,其中封装了一些存储应用数据的常用数据库操作,如 创建 、打开 以及 更新数据库 等。
SQLiteOpenHelper 类的常用方法
构造方法
SQLiteOpenHelper (Context context, //用来打开或创建一个数据库
String name, //用来指定数据库文件,若为 null 则指内存中的数据库
SQLiteDatabase.CursorFactory factory, //用来创建游标 Cursor 对象,若为 null 则使用默认的
int version) //数据库版本号,应为从 1 开始的递增整数值。
Tips:
关于版本号:
SQLiteOpenHelper
类有着管理不同版本数据库结构的能力。如果应用当前数据库版本更老,会通过 onUpgrade(SQLiteDatabase, int, int)
来更新数据库版本;反之如果当前应用数据库版本更新,则会通过 onDowngrade(SQLiteDatabase, int, int)
对数据库版本进行降级。
因此在实际应用中,每次对数据库结构做出调整后,都应该增加版本号常量。
公开的成员方法
//关闭任何已打开的数据库对象
void close ()
//创建或打开数据库
SQLiteDatabase getReadableDatabase ()
//创建或打开一个可读、可写的数据库
SQLiteDatabase getWritableDatabase ()
//配置数据库连接
void onConfigure (SQLiteDatabase db)
//第一次创建数据库时调用。数据库表的创建以及表的初始内容的填充 在这里完成。
void onCreate (SQLiteDatabase db)
//数据库降级
void onDowngrade (SQLiteDatabase db,
int oldVersion,
int newVersion)
//数据库升级
void onUpgrade (SQLiteDatabase db,
int oldVersion,
int newVersion)
Tips:
一般情况下,getReadableDatabase ()
和 getWritableDatabase ()
方法返回的是同一个对象,但如果出现一些极端情况(如硬盘满了),那么调用 getReadableDatabase ()
方法返回的就是一个只读的数据库。
这两种方法都会花费较长的时间,因此官方不建议从主线程(包括
ContentProvider.onCreate()
)中调用。
SQLiteDatabase 类常用方法
执行 SQL 语句
/**
* execSQL()
* 作用: 执行一个非 SELECT 的 SQL 语句或任何其他返回数据的 SQL 语句
* @param String: 要执行的SQL语句。不支持以分号分隔的多个语句
* Throws SQLException: 当传入的 String 无效时
*/
void execSQL(String sql)
官方鼓励开发人员尽可能使用
SQLiteDatabase
内嵌的insert()
、update()
方法来取代传统的 SQL 语句,但是博主 Carson_Ho 在相关文章中却建议多使用 SQL 语句(因为相对官方提供的方法更为简单、通用)。至于具体实际应用中使用哪种为多,我也不知道了。。这里就先挖个坑吧,等经验多了再回过头来补充我自己的观点。
插入
/**
* insert()
* 作用: 向数据库中插入一行数据
* 返回值: long 型。返回新插入的行数,如果插入过程出错则返回 -1
* @param table: 指定表的名称
* @param nullColumHack: 可选的; 可能是null。SQL不允许在不命名至少一个列名的
情况下插入空行。如果您提供的values是空的,则不知道列名称,并且无法插入空行。如
果未设置为 null ,则该 nullColumnHack 参数提供可为空的列名称的名称,以便在您
values 为空时显式插入 null
* @param values: ContentValues - 此映射包含行的初始列值。键应该是列名,值应该是列值
*/
long insert (String table,
String nullColumnHack,
ContentValues values)
//下面语句的意思是:向名为 SQLTest 的表中插入 id = 1, name = "张三" 的记录
ContentValues value = new ContentValues();
value.put("id", 1);
value.put("name", "张三");
mDatabase.insert("SQLTest", null, value);
删除
/**
* delete()
* 作用: 删除数据库中的行
* 返回值: int 型。如果传入的是 where 子句那么返回受到影响的行数,否则返回 0 。要
删除所有行并获取总数则传入 1 作为 where 子句
* @param table: 指定表的名称
* @param whereClause: 删除时要应用的可选 where 子句。传递null将删除所有行
* @param whereArgs: 如果在 where 子句中包含 ? ,它将被 whereArgs 中的值替换。
这些值将会被绑定成为字符串类型
*/
int delete (String table,
String whereClause,
String[] whereArgs)
//下面语句的意思是:从名为 SQLTest 的表中删除属性 id 值为 1 的行
mDatabase.delete("SQLTest", "id=?", new String[]{"1"});
修改
/**
* update()
* 作用: 更新数据库中的行
* 返回值: int 型。返回受影响的行数
* @param table: 指定表的名称
values 为空时显式插入 null
* @param values: ContentValues - 此映射包含行的初始列值。键应该是列名,值应该是列值
* @param whereClause: 删除时要应用的可选 where 子句。传递null将删除所有行
* @param whereArgs: 如果在 where 子句中包含 ? ,它将被 whereArgs 中的值替换。
这些值将会被绑定成为字符串类型
*/
int update (String table,
ContentValues values,
String whereClause,
String[] whereArgs)
//下面语句的意思是将名为 SQLTest 的表中, id=1 的元组的 name 值改为 "李四"
ContentValues value = new ContentValues();
value.put("name", "李四");
mDatabase.update("SQLTest", value1, "id=?", new String[]{"1"});
查询
/**
* query()
* 作用: 查询给定的 URL,返回 Cursor 结果集
* 返回值: 一个 Cursor 对象
* @param distinct: 消除相同行
* @param table: 指定表的名称
* @param columns: 要返回的列的列表(不建议为 null ,防止直接从内存中读取数据)
* @param selection: 一个过滤器,声明要返回哪些行,格式化为 SQL WHERE 子句(不包
括 WHERE 本身)。传入 null 将返回给定表的所有行
* @param selectionArgs: 如果在 selection 中包含了 ? ,那么它将被 selectionArgs 中的值替换
* @param groupBy: 一个过滤器,声明如何对行进行分组,格式化为 SQL GROUP BY 子句(不包
括 GROUP BY 本身)。传入 null 将导致行不被分组。
* @param having: 一个过滤器,声明要在游标中包含哪些行组,如果正在使用行分组,则格式化为
SQL HAVING 子句(不包括 HAVING 本身)。传入 null 将导致包含所有行组,并且在未使用行分
组时是必需的
* @param orderBy: 如何对行进行排序,格式化为 SQL ORDER BY 子句(不包括 ORDER BY 本身)。
传入 null 将使用默认排序顺序,该顺序可能是无序的
* @param limit: 限制查询返回的行数,格式为 LIMIT 子句。传入 null 表示没有 LIMIT 子句
*/
Cursor query (boolean distinct,
String table,
String[] columns,
String selection,
String[] selectionArgs,
String groupBy,
String having,
String orderBy,
String limit)
//query() 还有其他类似结构的方法,由于是部分参数的变化,这里就不一一列出了
由于这里涉及到了 Cursor
,因此要对查询结果进行进一步的操作就需要利用 Cursor
给出的方法,这里直接列出常用方法不再做多的说明:
//下面语句的意思是:将名为 SQLTest 的表中 id=1 的 "id" 列和 "name" 列返回给游标 Cursor
Cursor c = mDatabase.query(null, "SQLTest",
new String[]{"id", "name"},
"id=?",
new String[]{"1"},
null, null, null);
c.move(int offset); //以当前位置为参考,移动到指定行
c.moveToFirst(); //移动到第一行
c.moveToLast(); //移动到最后一行
c.moveToPosition(int position); //移动到指定行
c.moveToPrevious(); //移动到前一行
c.moveToNext(); //移动到下一行
c.isFirst(); //是否指向第一条
c.isLast(); //是否指向最后一条
c.isBeforeFirst(); //是否指向第一条之前
c.isAfterLast(); //是否指向最后一条之后
c.isNull(int columnIndex); //指定列是否为空(列基数为0)
c.isClosed(); //游标是否已关闭
c.getCount(); //总数据项数
c.getPosition(); //返回当前游标所指向的行数
c.getColumnIndex(String columnName); //返回某列名对应的列索引值
c.getString(int columnIndex); //返回当前行指定列的值
Demo
本来想着把 Demo
放到 github
上的,但是由于代码实现起来较为容易,也没有这个必要,这里就不再放出了。
参考资源:
Android API
Android 编程权威指南 [美]Phillips,B. [美]Hardy,B. [译]王明发 (人民邮电出版社)
Android :SQLlite数据库 使用手册 -- Carson_Ho