说说 Android 中的 SQLite 数据库

SQLite 是一款轻量级的关系型数据库,它的运算速度非常快, 占用资源很少,通常只需几百 K 的内存就足够了,因而特别适合在移动设备上使用。它不仅支持标准的 SQL 语法,还遵循了数据库的 ACID 事务。这套数据库可是内置于 Android 系统中的哦O(∩_∩)O哈哈~

当需要存储大量复杂的关系型数据时,就要用到关系型数据库啦。

1 创建数据库

Android 提供了一个 SQLiteOpenHelper 帮助类,借助这个类可以非常简单地对数据库进行创建与升级。

SQLiteOpenHelper

SQLiteOpenHelper 是一个抽象类,所以我们需要创建一个类去继承它并且重写它的两个抽象方法,即 onCreate() 和 onUpgrade(),去实现创建、升级数据库的逻辑。

创建或打开一个现有的数据库(若已存在则打开,否则创建一个新库),并返回一个可对数据库进行读写操作的对象的实例方法有两种(getReadableDatabase、getWriableDatabase),它们之间的区别是,当数据库不可写入的情况下(如磁盘空间已满):

方法 区别
getReadableDatabase() 返回的对象将以只读的方式去打开数据库。
getWriableDatabase() 抛出异常。

SQLiteOpenHelper 中的一个构造函数是这样的:

SQLiteOpenHelper(Context context, String name, CursorFactory factory, int version)
参数 说明
context 上下文
name 数据库名
factory 自定义游标,不需要就传入 null
version 当前数据库的版本号,用于升级数据库

构建出 SQLiteOpenHelper 的实例后,再调用它的 getReadableDatabase() 或 getWritableDatabase() 方法就能够创建数据库咯,数据库文件会存放在 /data/data/<package name>/databases/ 的目录下。 此时,重写的 onCreate() 方法也会得到执行,可以在这里处理一些创建表的逻辑。

假设我们需要建立一个名为 People.db 的数据库,然后在这个数据库中新建一张 people 表,表中有 id(主键)、名字、年龄、体重等字段。建表语句如下:

create table people( 
id integer primary key autoincrement,
name text,
age integer,
weight real)
数据类型 说明
integer 整型
real 浮点型
text 文本类型
blob 二进制类型

primary key autoincrement:表示设置某个字段为主键并且自增长。

PeopleDatabaseHelper 类:

public class PeopleDatabaseHelper extends SQLiteOpenHelper {

    /**
     * 建表语句
     */
    public static final String CREATE_SQL="create table people( id integer primary key autoincrement,name text,age integer,weight real)";

    private Context context;

    public PeopleDatabaseHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
        super(context, name, factory, version);
        this.context=context;
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(CREATE_SQL);
        Toast.makeText(context, "建表成功", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    }
}

我们在 onCreate 方法中 使用了 execSQL 来执行建表语句 ,这样就可以在创建数据库之后,创建需要的表。

调用语句:

 final PeopleDatabaseHelper helper=new PeopleDatabaseHelper(this,"People.db",null,1);
helper.getWritableDatabase();

可以使用 adb shell 来查看数据库与表的创建情况。

adb 是 Android SDK 自带的调试工具,可以直接对连接在电脑上的手机或者模拟器进行开发调试工作。它的安装方法请参见 在 Android Device Monitor 的 File Explorer 中,无法打开某些文件夹的解决方法

在命令行界面,使用命令 adb shell 进入设备控制台(先使用 adb root 获得访问权限):

设备控制台

进入目录命令的格式为:

cd /data/data/[包名]/databases/

这里为 cd /data/data/net.deniro.android.databasetest/databases/

进入目录

使用命令 ls 查看当前目录下的文件:

*.db:是我们创建的数据库。
*.db-journal:是为了让数据库能够支持事务所产生的临时日志文件,一般情况下,它为 0 字节。

使用 sqlite3 数据库名 来打开数据库,并使用 .table 命令来查看目前的数据库中有哪些表:

使用命令 .schema 可以查看这些表的创建语句:

键入 .exit 或 .quit 就可以退出 sqlite,再次键入 .exit 就会退出设备控制台,是不是很简单呀O(∩_∩)O哈哈~

2 升级数据库

可以在继承自 SQLiteOpenHelper 类的 onUpgrade 方法中,对数据库进行升级。

假设我们需要新增一张行业表,建表语句为:

create table Industry(
  id integer primary key autoincrement,
  industry_name text,
  industry_code integer)

修改原来的代码:

/**
 * 创建行业表
 */
public static final String CREATE_INDUSTRY_SQL = "create table Industry(  id integer primary key autoincrement,  industry_name text,  industry_code integer)";

 @Override
public void onCreate(SQLiteDatabase db) {
    db.execSQL(CREATE_PEOPLE_SQL);
    db.execSQL(CREATE_INDUSTRY_SQL);
    Toast.makeText(context, "建表成功", Toast.LENGTH_SHORT).show();
}

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    dropTable(db, "People");
    dropTable(db, "Industry");
    onCreate(db);
}

/**
 * 删除表
 *
 * @param db
 * @param tableName 表名称
 * @return
 */
private void dropTable(SQLiteDatabase db, String tableName) {
    db.execSQL("drop table if exists " + tableName);
}

这里首先在 onCreate 方法中,创建行业表;接着在 onUpgrade 方法中,删除相应的表,并调用 onCreate,重新创建表结构。

最后在 PeopleDatabaseHelper 的构造函数中,把版本号(最后一个参数)改为 2:

创建成功后,可以通过之前介绍的 adb shell 方法查看新创建的表结构:


3 新增数据

对数据进行的操作一般有四种,即 CRUD:添加(Create),查询(Retrieve),更新(Update),删除(Delete)。

SQLiteOpenHelper 中的 getReadableDatabase() 或 getWritableDatabase() 方法都会返回一个 SQLiteDatabase 对象,借助这个对象可以对数据进行 CRUD 操作。

SQLiteDatabase 类包含 insert 方法:

public long insert(String table, String nullColumnHack, ContentValues values)
参数名 说明
table 表名
nullColumnHack 在未指定添加数据的情况下给某些可为空的列自动赋值,一般传入 null。
values 是一个ContentValues 对象,它包含一系列的 put() 方法重载,用于向 ContentValues 中添加数据(列名与列的内容一一对应)。

新增操作:

SQLiteDatabase db= helper.getWritableDatabase();

//新增
ContentValues values=new ContentValues();
values.put("name","deniro");
values.put("age",22);
values.put("weight",70);
db.insert("People",null,values);

因为 id 为自增长的列,所以这里无须赋值。

查看结果:

select * from People;

4 更新数据

SQLiteDatabase 类包含 update 方法:

public int update(String table, ContentValues values, String whereClause, String[] whereArgs) 
参数名 说明
table 表名
values ContentValues 对象,存放要更新的数据
whereClause where SQL 语句(占位符形式)
whereArgs where SQL 语句中的参数,与语句中的占位符一一对应

调用代码:

SQLiteDatabase db= helper.getWritableDatabase();

//修改
ContentValues values=new ContentValues();
values.put("age",24);
db.update("People",values,"name = ?",new String[]{"deniro"});

这里把所有 name = 'deniro' 的数据中的 age 都更新为 24。

更新结果:


5 删除数据

SQLiteDatabase 类中包含 delete 方法来删除数据:

public int delete(String table, String whereClause, String[] whereArgs) 
参数名 说明
table 表名
whereClause where SQL 语句(占位符形式)【可选】
whereArgs where SQL 语句中的参数,与语句中的占位符一一对应【可选】

调用代码:

SQLiteDatabase db = helper.getWritableDatabase();

//删除
db.delete("People", "name = ?", new String[]{"deniro"});

执行后,在 sqlite 命令中就会发现,数据被删除咯。

6 查询数据

SQLiteDatabase 中提供了 query() 方法用于查询数据。 这个方法的参数非常复杂,最短的一个方法重载也需要传入七个参数。

query 的各种重载方法
 public Cursor query(String table, String[] columns, String selection,
            String[] selectionArgs, String groupBy, String having,
            String orderBy)
参数名 说明 示例
table 表名 from table_name
columns 列名 select column1,column2
selection where 条件 where column = value
selectionArgs where 条件中的占位符参数值 -
groupBy 需要分组的列 group by column
having 分组条件 having column = value
orderBy 排序条件 order by column1,column2

返回 Cursor 对象,查询到的数据可以从这个对象中取出。

调用代码:

SQLiteDatabase db = helper.getWritableDatabase();

//查询
Cursor cursor = db.query("People", null, null, null, null, null, null);
if (cursor.moveToFirst()) {
    do {
        Log.d(TAG, "name: " + cursor.getString(cursor.getColumnIndex("name")));
        Log.d(TAG, "age: " + cursor.getInt(cursor.getColumnIndex("age")));
    } while (cursor.moveToNext());
}
cursor.close();

得到 Cursor 对象后,使用 moveToFirst 把数据指针移到第一行,然后进入循环。getColumnIndex 获取某一列在表中的位置索引,然后把这个索引传入相应类型的取值方法中(比如 int 型,使用 getInt 方法),就可以读取数据啦。最后记得关闭 cursor。

7 使用原生 SQL 操作数据库

我们也可以直接使用原生 SQL 来完成前面说过的新增、修改与删除操作,这就是 SQLiteDatabase 类中的 execSQL 方法:

public void execSQL(String sql, Object[] bindArgs)
参数名 说明
sql SQL 语句
bindArgs 占位符绑定的参数

查询数据可以使用 SQLiteDatabase 类中的 rawQuery方法:

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

参数说明与 execSQL 方法类似,是不是很简单呀O(∩_∩)O哈哈~

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

推荐阅读更多精彩内容