Android 移动开发 | 应用数据存储与访问之SQLite数据库

1. 前言

Sqlite3是SQLite数据库的版本之一,是Android提供的一个数据库管理工具,它位于Android SDK的platform-tools目录下,通过它可以在命令行手动创建和操作SQLite数据库。

2. SQLite3 简介

SQLite是一个进程内的库,也是一个轻量级的关系型数据库,实现了自给自足的、无服务器的、零配置的、事务性的 SQL 数据库引擎。 不仅支持标准SQL语法,还遵循ACID(数据库事务)原则,无需账号,使用起来非常方便!

3. SQLite3 安装

本文以在Windows 下为例

我们先前安装Android Studio 的时候Android 自己先下载配置好了platform-tools,这个包已经包含了sqlite3,所以你就不需要再单独下载sqlite3,请跳过3. SQLite3 安装
在这里插入图片描述
如果在命令行下输入sqlite3 没有版本信息提示的话,请看下面的安装步骤进行安装:

SQLite3官网下载地址:https://www.sqlite.org/download.html

  • 下载
    需要从 Windows 区下载预编译的二进制文件: sqlite-tools-win32-.zip 和 sqlite-dll-win32-.zip 压缩文件;
    在这里插入图片描述

  • 解压
    自己在磁盘目录下创建一个文件夹(我这里放在D:sqlite3下),并在此文件夹下解压上面两个压缩文件,将得到 sqlite3.def、sqlite3.dll 和 sqlite3.exe 文件。

  • 配置环境变量
    添加 D:sqlite3(这里是你解压目录)到 PATH环境变量
    在这里插入图片描述

  • 最后在命令提示符下,使用 sqlite3 命令,将显示如下版本相关信息即安装成功。
    在这里插入图片描述

4. SQLite3 的使用

Android SDK 提供一个 sqlite3 shell 工具,你可以使用该工具浏览表内容、运行 SQL 命令以及在 SQLite数据库中执行其他实用操作。

4.1 启动SQLite3

  • 打开cmd命令窗口,使用cd进入到你的platform-tools目录下或者是你上面解压的sqlite3目录下
    -
  • 切换到sqlite3的所在目录,输入adb shell命令,进入到shell命令模式。
    在这里插入图片描述

注意:进入shell 命令模式需要把手机模拟器打开并且处于开机状态,否则会出现上面错误(error: no devices/emulators found):提示找不到设备或者模拟器,和device offline

  • 输入sqlite3命令启动sqlite3工具。启动成功如下:
    在这里插入图片描述
    sqlite3支持SQL语句,sqlite3数据库启动成功后可以在里面使用sql语句进行数据库表的创建等一系列操作。

  • 退出sqlie3数据库可以使用.exit命令,退出数据库后会返回shell界面,退出shell命令模式。

  • 使用 shell 命令发出单个命令:

adb [-d |-e | -s serial_number] shell shell_command
  • 使用 shell 命令在设备上启动交互式 shell:
adb [-d | -e | -s serial_number] shell
  • 要退出交互式 shell,请按 Ctrl + D 键或输入 exit
    在这里插入图片描述

4.2 建立数据库目录

数据库存放于应用程序各自的/data/data/包名/databases目录下,下面使用命令行手动创建数据库,创建数据库目录可以在Shell命令模式下使用mkdir命令完成。
例如,在/data/data/com.example.file目录下创建目录databases,命令如下:

mkdir /data/data/com.example.file/databases

4.3 创建/打开数据库文件

数据库位于每个应用程序的databases目录,每一个数据库文件是单独存放的,使用“sqlite3+数据库名”这样的方式打开数据库文件,如果指定的文件不存在,自动创建对应文件。创建数据库文件需要两个步骤,具体步骤如下:

  • 步骤1:使用cd命令进入到数据库目录下,例如进入到我的databases目录下:
cd  /data/data/com.example.file/databases
  • 步骤2:创建db数据库文件,例如创建一个名为db的数据库文件:
sqlite3 db

4.4 操作数据库

SQLite不像其它数据库提供众多数据类型,它的常用数据类型有:integer整形、real浮点型、text文本型、blob表示二进制类型等。另外primary key表示将id列设为主键,autoincrement关键字表示id列是自增长的。

sqlite3工具提供了对数据库操作的一些常用命令,具体如下:

命令 说明
create table 创建数据表。例如:create table user(id integer primary key autoincrement,name text not null,pass text);
.tables 显示全部数据
.schema 查看建立表时使用的SQL命令
insert into 添加数据。例如:insert into user valuse(null,‘李子’,‘123’);
select 查询数据。例如:select * from user;
update 更新数据。例如:updata user set pass=‘123’ where id=5;
delete 删除数据。例如:delete from user where id=1;

5. 代码操作数据库

5.1 创建数据库

Android为开发者提供了一个SqliteDatabase代表数据库,应用程序只要获取到SqliteDatabase对象便可以操作数据库,SqliteDatabase提供了openOrCreateDateabase()方法用于打开或创建一个数据库,其语法格式如下:

static SQLiteDatabase openOrCreateDatabase(File file, CursorFactory factory)

参数说明

  • file:用于指定数据库文件
  • factory:实例化一个数据库游标。
  • 游标(Cursor):是处理数据的一种方法,为了查看或者处理结果集中的数据,游标提供了在结果集中一次一行或者多行前进或向后浏览数据的能力。可以把游标当作一个指针,它可以指定结果中的任何位置,然后允许用户对指定位置的数据进行处理。

使用openOrCreateDateabase()方法创建数据库,例如创建一个data的数据库文件具体代码如下:

SQLiteDatabase db = SQLiteDatabase.openDatabase("data.db",null);

5.2 操作数据库

创建好数据库以后则需要操作数据,操作数据涉及添加、删除、更新和查询,SQLiteDatabase类提供了一系列操作数据的方法,当然也可以通过执行SQL语句来完成,这里建议使用SQLiteDatabase类提供的方法,因为这些方法封装了SQL语句更加简单易用。

insert()—添加数据

insert()方法用于向数据表中插入数据,其语法格式如下:

insert(String table,String nullColumnHack,ContentValues  values)

参数说明:

  • table:指定一个表名不能为null
  • nullColumnHack:用于指定values参数为空时,将哪个字段设置为null,如果values不为空,则该参数值可以设置为null(可选参数)
  • values:指定具体的字段值,它相当于Map集合,也是通过键值对的形式存储值的。

delete()—删除数据

delete()方法用于从表中删除数据,其语法格式如下:

delete(String table,String whereClause,String[]  whereArgs)

参数说明:

  • table:指定一个表名不能为null
  • whereClause:用于指定条件语句,可以使用占位符(?)。
  • whereArgs:当上一个参数没有占位符时,该参数用于指定各占位参数的值,如果不包括占位符,该参数可以设置为null。

update()—更新数据

update()方法用于更新表中的数据,其语法格式如下:

update(String table,ContentValues values,String whereClause,String[]  whereArgs)

参数说明:

  • table:指定一个表名不能为null
  • values:指定要更新的字段及对应的字段值,它也是通过键值对的形式存储。
  • whereClause:指定条件语句,可以使用占位符(?)。
  • whereArgs:当上一个参数没有占位符时,该参数用于指定各占位参数的值,如果不包括占位符,该参数可以设置为null。

query()—查询数据

query()方法用于查询表中的数据,其语法格式如下:

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

参数说明:

  • table:指定一个表名不能为null
  • columns:要查询的列名,可以是多个,可以为null,表示查询所有列
  • selection:查询条件,比如id=? and name=? 可以为null
  • selectionArgs:对查询条件赋值,一个占位符对应一个值,按顺序可以为null
  • groupBy:用于指定分组方式。
  • having:用于指定having条件
  • orderBy:用于指定排序方式,为空表示默认排序。
    查询数据返回的是一个Cursor(游标)对象,这个对象虽然保存着查询结果,但是并不是数据集合的完整复制,只是一个数据集指针,通过这个指针的移动才可以获取数据集合中的数据。

Curosr类的常用方法举例如下:

方法 说明
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) 返回当前行指定列的值

6. SQLiteOpenHelper类

Android为了更好的管理数据库,Android 提供了对 SQLite 数据库的完整支持。专门提供了一个SQLiteOpenHelper类,借助这个类可以更好的操作数据库。Android提供了SQLiteOpenHelper 类包含一组用于管理数据库的实用 API。SQLiteOpenHelper类可以创建数据库与版本管理,SQLiteOpenHelper类中的onCreate( )方法可以帮我们在第一次启动app的时候创建好数据库表;而当我们的应用进行升级需要修改数据库表的结构时通过onUpgrade( )来帮我们实现对数据库表进行的更新。

6.1 SQLiteOpenHelper类的重要方法

SQLiteOpenHelper

SQLiteOpenHelper:是一个抽象类,使用它需要创建一个类继承自它的子类,SQLiteOpenHelper提供了两个抽象方法,它们分别是onCreate()方法和onUpgrade()方法,需要在子类里实现这两个方法,然后在这两个方法中实现创建、升级数据库的逻辑。

SQLiteOpenHelper中还有两个非常重要的方法:getReadableDatabase()方法和getWriteableDatabase()方法。

  • getReadableDatabase()方法的特性:
    (1) 它会调用并返回一个可以读写数据库的对象。
    (2) 在第一次调用时会调用onCreate的方法。
    (3) 当数据库存在时会调用onOpen方法。
    (4) 结束时调用onClose方法。
  • getWriteableDatabase()方法的特性:
    (1) 它会调用并返回一个可以读写数据库的对象。
    (2) 在第一次调用时会调用onCreate的方法。
    (3) 当数据库存在时会调用onOpen方法。
    (4) 结束时调用onClose方法。

两个方法的区别:

(1) 两个方法都是返回读写数据库的对象,但是当磁盘已经满了时,getWritableDatabase会抛异常,而getReadableDatabase不会报错,它此时不会返回读写数据库的对象,而是仅仅返回一个读数据库的对象。

(2) getReadableDatabase会在问题修复后继续返回一个读写的数据库对象。
SQLiteOpenHelper有两个构造方法,一般默认使用下面这个:
public SQLiteOpenHelper(Context context, String name, CursorFactory factory, int version)
context:上下文对象。
name:数据库的名称。
factory:允许在查询数据库的时候返回一个自定义的Cursor,一般输入null即可。
version:数据库的版本,可用于数据库升级操作。

SQLiteOpenHelper类操作数据库的常用方法如下:

方法 说明
onCreate() 创建数据库
onUpgrade() 升级数据库
close() 关闭所有打开的的数据库是对象
execSQL() 可以进行增删改操作,不能进行查询操作
query(),rawQuery() 查询数据库
insert() 插入数据
delete() 删除数据

SQLiteDatabase

SQLiteDatabase:即数据库访问类,我们也可以直接使用SQLiteDatabase提供的相关方法,可以通过该类的对象来对数据库做一些增删改查的操作。下面是SQLiteDatabase的方法:

  • execSQL(SQL,Object[]):使用带占位符的SQL语句,这个是执行修改数据库内容的sql语句用的
  • rawQuery(SQL,Object[]):使用带占位符的SQL查询操作 另外前面忘了介绍下Curosr这个东西以及相关属性,这里补充下: ——Cursor对象有点类似于JDBC中的ResultSet,结果集!使用差不多,提供一下方法移动查询结果的记录指针:
  • move(offset):指定向上或者向下移动的行数,整数表示向下移动;负数表示向上移动!
  • moveToFirst():指针移动到第一行,成功返回true,也说明有数据
  • moveToLast():指针移动到最后一样,成功返回true;
  • moveToNext():指针移动到下一行,成功返回true,表明还有元素!
  • moveToPrevious():移动到上一条记录
  • getCount( )获得总得数据条数
  • isFirst():是否为第一条记录
  • isLast():是否为最后一项
  • moveToPosition(int):移动到指定行

Cursor

Cursor:游标,有点类似于JDBC里的resultset,结果集!可以简单理解为指向数据库中某 一个记录的指针!

6.2 SQLiteOpenHelper类操作数据库

SQLiteOpenHelper类操作数据库具体步骤如下:

  • 步骤1:创建一个继承自SQLiteOpenHelper类的子类,例如:
    public class MySQLiteOpenHelper extends SQLiteOpenHelper
  • 步骤2:重写onCreat()、onUpgrade()两个方法。
  • 步骤3:在MainActivity里实现需要进行的数据库操作,增加、删除、查找、修改等操作。

6.3 为应用创建数据库

使用SQLiteOpenHelpe创建数据库步骤方法:

  • 创建一个继承SQLiteOpenHelper的子类;
  • 在该类的构造方法的super中设置好要创建的数据库名,版本号;
  • 重写onCreate( )onUpgrade( )两个方法:onCreate( )方法用来创建表结构,onUpgrade( )方法用来定义版本号发生改变后执行的操作;
public class FeedReaderDbHelper extends SQLiteOpenHelper {
    
    
   // 如果更改数据库架构,则必须增加数据库版本号.
    public static final int DATABASE_VERSION = 1;
    public static final String DATABASE_NAME = "mydb.db";

    public FeedReaderDbHelper(Context context) {
    
    
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }
    public void onCreate(SQLiteDatabase db) {
    
    
        db.execSQL(SQL_CREATE_ENTRIES);
    }
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    
    
        db.execSQL(SQL_DELETE_ENTRIES);
        onCreate(db);
    }
    public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    
    
        onUpgrade(db, oldVersion, newVersion);
    }
}

onUpgrade()方法中由于该数据库只是联机数据的缓存,因此它的升级策略是简单地丢弃数据并重新开始。

  • 访问你的数据库时,要先实例化 SQLiteOpenHelper 的子类。
FeedReaderDbHelper dbHelper = new FeedReaderDbHelper(getContext());

6.4 将信息添加到数据库

通过将 ContentValues 对象传递给 insert()方法,将数据插入到数据库中:

// 以写模式获取数据存储库
SQLiteDatabase db = dbHelper.getWritableDatabase();

// 创建一个新的值映射,其中列名是键
ContentValues values = new ContentValues();
values.put(FeedEntry.COLUMN_NAME_TITLE, title);
values.put(FeedEntry.COLUMN_NAME_SUBTITLE, subtitle);

// //插入新行的值,返回新行的主键值
long newRowId = db.insert(FeedEntry.TABLE_NAME, null, values);

insert() 参数说明:

  • 第一个参数是:表名。

  • 第二个参数将指示框架在 ContentValues 为空(即你没有 put 任何值)时应执行哪些操作。如果您指定列名称,框架会插入一行,并将该列的值设置为null。如果你指定 null(如此代码示例所示),框架在没有值时不会插入行。

insert() 方法会返回新创建行的 ID;如果在插入数据时出错,会返回 -1。如果你的数据与数据库中已有的数据之间存在冲突,就会出现这种情况。

6.5 从数据库中读取信息

读取信息需要使用query()方法,向其传递你的选择条件和所需的列。该方法合并了 insert()update()两个方法,不过列的列表定义是要提取的数据(“xx值”),而不是要插入的数据。query()方法查询结果会包含在 Cursor 对象中返回给你。

SQLiteDatabase db = dbHelper.getReadableDatabase();

// 定义一个projection 指定从数据库中的哪些列读取数据
String[] projection = {
    
    
    BaseColumns._ID,
    FeedEntry.COLUMN_NAME_TITLE,
    FeedEntry.COLUMN_NAME_SUBTITLE
    };

// 在“title”=‘My Title’的情况下,筛选查询结果
String selection = FeedEntry.COLUMN_NAME_TITLE + " = ?";
String[] selectionArgs = {
    
     "My Name" };

// 设置查询结果在结果游标中排序的方式
String sortOrder =
    FeedEntry.COLUMN_NAME_SUBTITLE + " DESC";

Cursor cursor = db.query(
    FeedEntry.TABLE_NAME,   // 要查询的表
    projection,             // 要返回的列数组(传递NULL以获取所有列)
    selection,              // WHERE子句的列
    selectionArgs,          // WHERE子句的值
    null,                   // 不要对行进行分组
    null,                   // 不要按行组过滤
    sortOrder               // 排序顺序
    );

第三个参数和第四个参数(selection 和 selectionArgs)会合并起来创建一个 WHERE 子句。由于这两个参数是与选择查询分开提供的,因此它们在合并之前会进行转义。这样一来,你的选择语句就不受 SQL 注入的影响。

使用SQL语句操作数据库:
通过使用 Cursor moveXXX 方法来查看游标中的某一行,前提是必须始终在开始读取值之前调用该方法。由于游标从位置 -1开始,因此调用 moveToNext() 会将“读取位置”置于结果的第一个条目上,并返回光标是否已经过结果集中的最后一个条目。对于每一行,都可以通过调用 Cursor getXXX方法(例如 getString() 或 getLong())读取列的值。对于每个 get XXX方法,必须传递所需列的索引位置,我们可以通过调用getColumnIndex()getColumnIndexOrThrow() 获取该位置。遍历结果之后,请对游标调用 close()以释放其资源。例如,以下代码展示了如何获取存储在光标中的所有项目 ID 并将其添加到列表中:

List itemIds = new ArrayList<>();
while(cursor.moveToNext()) {
    
    
  long itemId = cursor.getLong(
      cursor.getColumnIndexOrThrow(FeedEntry._ID));
  itemIds.add(itemId);
}
cursor.close();

6.6 从数据库中删除信息

如需从表中删除行,我们需要提供选择条件,以标识 delete()方法的目标要删除的行。该机制与 query()方法的目标选择参数的工作方式相同。它将选择规范划分为选择子句和选择参数。子句定义要查看的列,并允许你合并列测试。参数是要测试的值,这些值绑定到子句中。由于结果的处理方式与常规 SQL 语句的处理方式不同,因此不受 SQL 注入的影响。

// 定义查询的 “where” 部分
String selection = FeedEntry.COLUMN_NAME_TITLE + " LIKE ?";
// 按占位符顺序指定参数
String[] selectionArgs = {
    
     "MyName" };
// 发出SQL语句
int deletedRows = db.delete(FeedEntry.TABLE_NAME, selection, selectionArgs);

delete()方法的返回值表示从数据库中删除的行数。

6.7 更新/插入数据库

如果需要修改数据库值的子集,使用 update()方法。
更新表可将insert()ContentValues语法与 delete()的 WHERE 语法相结合。

SQLiteDatabase db = dbHelper.getWritableDatabase();

// 一列的新值
String title = "MyNewName";
ContentValues values = new ContentValues();
values.put(FeedEntry.COLUMN_NAME_TITLE, title);

// 要更新的行,根据标题
String selection = FeedEntry.COLUMN_NAME_TITLE + " LIKE ?";
String[] selectionArgs = {
    
     "MyOldName" };

int count = db.update(
    FeedReaderDbHelper.FeedEntry.TABLE_NAME,
    values,
    selection,
    selectionArgs);

update() 方法与delete()方法类似,它返回值是数据库中受影响的行数。

6.8 保留数据库连接

由于在数据库关闭时,调用getWritableDatabase()getReadableDatabase() 的成本比较高,因此只要你有可能需要访问数据库,就应保持数据库连接处于打开状态。通常情况下,最好在发出调用的 ActivityonDestroy()中关闭数据库。

@Override
protected void onDestroy() {
    
    
    dbHelper.close();
    super.onDestroy();
}

更多详细内容参考学习Android官方文档: https://developer.android.google.cn/training/data-storage/sqlite

猜你喜欢

转载自blog.csdn.net/weixin_43853746/article/details/110130731
今日推荐