Android SQLite

【Android SQLite】

SQLite 简介

SQLite 是一款内置到移动设备上的轻量型的数据库,是遵守 ACID(原子性、一致性、隔离性、持久 性)的关联式数据库管理系统,多用于嵌入式系统中。
SQLite 数据库是无类型的,可以向一个 integer 的列中添加一个字符串,但它又支持常见的类型比如: NULL,VARCHAR, TEXT, INTEGER, BLOB, CLOB 等。
Android 系统内置了 SQLite,并提供了一系列 API 方便对其进行操作。

使用 SQLiteOpenHelper 创建数据库

SQLiteOpenHelper 是 Android 提供的一个抽象工具类,负责管理数据库的创建、升级工作。如果我们 想创建数据库,就需要自定义一个类继承 SQLiteOpenHelper,然后覆写其中的抽象方法。

创建 SQLiteOpenHelper 类

【文件 1-1】 MySQLiteOpenHelper.java

public class MySQLiteOpenHelper extends SQLiteOpenHelper {
    private static final String TAG = "MySQLiteOpenHelper";
    //定义数据库文件名
    public static final String TABLE_NAME = "myuser.db";

    /**
     * @param context
     * @param name    数据库文件的名称
     * @param factory null
     * @param version 数据库文件的版本
     */
    private MySQLiteOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory,
                               int version) {
        super(context, name, factory, version);
    }

    // 对外提供构造函数
    public MySQLiteOpenHelper(Context context, int version) {
        //调用该类中的私有构造函数
        this(context, TABLE_NAME, null, version);
    }

    // 当第一次创建数据的时候回调方法
    @Override
    public void onCreate(SQLiteDatabase db) {
        Log.d(TAG, "onCreate");
//创建数据库表的语句
        String sql = "create table t_user(uid integer primary key not null, c_name varchar (20), c_age integer, c_phone varchar(20))";
        db.execSQL(sql);
    }

    // 当数据库升级是回调该方法
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        Log.d(TAG, "onUpgrade: oldVersion" + oldVersion + " newVersion=" + newVersion);
        String sql = "alter table t_user add c_money float";
        db.execSQL(sql);
    }

    // 当数据库被打开时回调该方法
    @Override
    public void onOpen(SQLiteDatabase db) {
        Log.d(TAG, "onOpen");
    }
}

注意:
上面的代码我们只是定义了一个 MySQLiteOpenHelper 类继承了 SQLiteOpenHelper 类。在 onCreate()方法中通过执行 sql 语句实现表的创建。

使用 SQLiteOpenHelper 类

在 Activity 中可以执行如【文件 1-2】所示代码。如果第一次执行,则会创建一个数据库文件,创建的数据库文件位/data/data/包名/databases/目录中。
【文件 1-2】 代码片段

    /* 通过构造函数创建一个 MySQLiteOpenHelper 对象,
    * 此时数据库文件还未创建   */
    MySQLiteOpenHelper openHelper = new MySQLiteOpenHelper(this, VERSION);
    // 调用以下任一方法可使数据库文件得以创建
    openHelper.getWritableDatabase();
 // openHelper.getReadableDatabase();
    //关闭资源
    openHelper.close();

注意:
如果 openHelper.getWritableDatabase();或者 openHelper.getReadableDatabase();是第一次被调用,那么数据库文件会被创建,否则只打开不创建。

创建的数据库文件如图 1-1 所示,包含两个文件,一个就是我们自定义的名称 myuser.db,另外一个 myuser.db-journal,该文件会被自动创建,是 sqlite 的一个临时的日志文件,主要用于 sqlite 数据库的事务 回滚操作。

图 1-1 database 文件

数据库的增删改查

以上创建了 MySQLiteOpenHelper 类,通过该类可以获取 SQLiteDatabase 对象。而 SQLiteDatabase对象则可是实现对数据库增删改查操作。

对数据库的增删改查我分为两种方式:

1、使用纯 SQL 语句实现

添加数据
// 纯 SQL 方式添加数据
//通过 SQLiteOpenHelper 对象获取 SQLiteDatabase
SQLiteDatabase database = mOpenHelper.getWritableDatabase();
String sql = "insert into t_user (c_name,c_age,c_phone) values (?,?,?)";
// 执行数据库,参数以 Object[]的形式传递
database.execSQL(sql, new Object[] { 
                "zhangsan" + new Random().nextInt(100),
                new Random().nextInt(30), 
                "" + (5550 + new Random().nextInt(100)) });
//关闭数据库释放资源
database.close();
删除数据
// 删除年龄小于 21 的用户
SQLiteDatabase database = mOpenHelper.getReadableDatabase();
String sql = "delete from t_user where c_age<?";
database.execSQL(sql, new Object[] { 21 });
database.close();
修改数据
SQLiteDatabase database = mOpenHelper.getWritableDatabase();
String sql = "update t_user set c_name=? where c_age=?"; 
database.execSQL(sql, new Object[] { "lisi", 25 });
database.close();
查询数据

【文件 1-6】 查询数据代码

public void query1(View view) {
    //将查询到的数据封装到 User 集合中
    ArrayList<User> users = new ArrayList<User>();
    //获取 SQLiteDatabase
    SQLiteDatabase database = mOpenHelper.getReadableDatabase();
    String sql = "select uid,c_name,c_age,c_phone from t_user where c_age<?";
    // 执行查询语句,返回游标对象,可以将游标看做指向结果集的指针
    Cursor cursor = database.rawQuery(sql, new String[]{"130"});
    // 游标的默认位置位于第一行数据的前面
    while (cursor.moveToNext()) {
        User user = new User();
        //从第 1 列获取 int 型数据,字段的顺序是由查询语句决定的
        int uid = cursor.getInt(0);
        //从第 2 列获取字符串数据
        String name = cursor.getString(1);
        //从第 3 列获取 int 型数据
        int age = cursor.getInt(2);
        String phone = cursor.getString(3);
        user.setAge(age);
        user.setName(name);
        user.setPhone(phone);
        user.setUid(uid);
        users.add(user);
    }
    cursor.close();
    database.close();
}

注意:
使用纯 SQL 语句操作适合 SQL 比较熟练的程序员。如果 SQL 掌握的不好,没关系,Android 提供了一套 API 可以帮助我们完成以上操作。

2、使用特有 API 实现

添加数据
//获取 SQLiteDatabase
SQLiteDatabase database = mOpenHelper.getWritableDatabase();
/* ContentValues底层是 Map 数据结构
* key 对应数据库表中字段
* value 是想插入的值 */
ContentValues values = new ContentValues();
values.put("c_name", "王五" + new Random().nextInt(10));
values.put("c_age", new Random().nextInt(50));
values.put("c_phone", "5556");
/*
* 第一个参数:表名,注意不是数据库名!
* 第二个参数:如果 ContentValues 为空,那么默认情况下是不允许插入空值的,
* 但是如果给该参数设置了一个指定的列名,那么就允许 ContentValues 为空,
*同时给该列插入 null 值。
* 第三个参数:要插入的数值,封装成了 ContentValues 对象\
* 返回 long 类型的值,代表该条记录在数据库中的 id */
long insert = database.insert(TABLE_NAME, null, values);
//释放资源
database.close();
删除数据
SQLiteDatabase database = mOpenHelper.getReadableDatabase();
/*
* 第一个参数:表名
* 第二个参数:删除条件,比如 c_age=?或者 c_age<?
* 第三个参数:参数,用于替换?
* 返回值:删除成功的个数 */
int delete = database.delete(TABLE_NAME, "c_age<?", new String[] { "25" });
database.close();
修改数据
SQLiteDatabase database = mOpenHelper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put("c_name", "wangwu");
// 将年龄等于 28 的姓名改为 wangwu
int update = database.update(TABLE_NAME, values, "c_age=?", new String[] { "28" });
database.close();
查询数据
ArrayList<User> users = new ArrayList<User>();
SQLiteDatabase database = mOpenHelper.getReadableDatabase();
/*
* 参数 1:表名
* 参数 2:要查询的字段
* 参数 3:查询条件
* 参数 4:条件中?对应的值
* 参数 5:分组查询参数
* 参数 6:分组查询条件
* 参数 7:排序字段和规则 */
Cursor cursor = database.query(TABLE_NAME, 
                new String[] {"uid", "c_name", "c_age", "c_phone" }, 
                "c_age<?", new String[] { "130" }, null, null, "c_age desc");
//对游标 Cursor 的遍历
while (cursor.moveToNext()) {
    User user = new User();
    int uid = cursor.getInt(0);
    String name = cursor.getString(1);
    int age = cursor.getInt(2);
    String phone = cursor.getString(3);
    user.setAge(age);
    user.setName(name);
    user.setPhone(phone);
    user.setUid(uid);
    users.add(user);
}
cursor.close();
database.close();

两种 SQLiteDatabase 的不同

SQLiteOpenHelper 有两个方法均可返回 SQLiteDatabase 对象:
一、getWritableDatabase()
该方法返回的对象和另外一个方法返回的对象没有任何差异,返回的对象对数据库都可以进行读、写操作,当磁盘已满或者权限不足的情况下该方法会抛出异常。

二、getReadableDatabase()
跟另外一个方法相比,在磁盘已满的情况下,该方法不会抛出异常,而是返回一个只读的数据库操作对象。
根据这两种方法返回对象的差异,如果需要对数据库进行查询操作则推荐使用后者,如果添加、修改、删除数据则推荐使用前者

数据库的升级和事务操作

数据库的升级

在创建 MySQLiteOpenHelper 对象的时候需要传递一个 int 类型的 version 参数,代表数据库的版本号,数值从 1 开始。如果在 new MySQLiteOpenHelper 对象的时候传递的 version 大于先去创建的 version,那 么就会导致系统回调 onUpgrade 方法,从而实现了数据库的升级。

事务的操作

在 SQLiteDatabase 提供了对事务的支持,处于事务中的操作都是“临时性”的,只有事务提交了 才会将数据保存到数据库
事务的使用不仅可以保证数据一致性,也可以提高批处理时的执行效率

SQLiteDatabase 提供的 beginTransaction()打开事务endTransaction()结束事务
注意:结束 事务并不代表事务提交,如果想让数据写入的数据库需要在结束事务前执行 setTransactionSuccessful()方法。这是事务提交的唯一方式。

如下:展示了当开启事务后,如果因为异常导致事务没有提提交,那么整个转账过程都不会成功。

//数据库的事务操作
SQLiteDatabase database = mOpenHelper.getReadableDatabase();
String sql = "update t_user set c_money=c_money-500 where c_name=?";
// 模拟转账
// 开启了事务,那么之后的操作都是在缓存中执行
database.beginTransaction();
database.execSQL(sql, new String[] { "wangwu" });

// 在事务中模拟一个异常的发生
int a = 1 / 0;
String sql2 = "update t_user set c_money=c_money+500 where c_name=?";
database.execSQL(sql2, new String[] { "lisi" });

// 只有执行该代码,才将缓存中的数据写到数据库中
database.setTransactionSuccessful();
database.endTransaction();
database.close();

如下:展示了如果批处理数据时,使用事务可以显著提高效率。运行结果见图 1-2。
【文件 1-13】 代码片段

// 测试批处理效率
public void testBatch(View view) {
    SQLiteDatabase database = mOpenHelper.getWritableDatabase();
// 普通方式添加 10000 条记录
    String sql = "insert into t_user (c_name,c_age,c_phone) values (?,?,?)";
    long startTime = SystemClock.currentThreadTimeMillis();
    for (int i = 0; i < 1000; i++) {
        database.execSQL(sql, new Object[] { "zhangsan" + new Random().nextInt(100),
                new Random().nextInt(30), "" + (5550 + new Random().nextInt(100)) });
    }
    System.out.println("普通模式耗时:"+(SystemClock.currentThreadTimeMillis()-startTime)+"毫秒");
// 开启事务的方式添加 1000 条记录
    startTime = SystemClock.currentThreadTimeMillis();
    database.beginTransaction();
    for(int i=0;i<1000;i++){
        database.execSQL(sql, new Object[] { "zhangsan" + new Random().nextInt(100),
                new Random().nextInt(30), "" + (5550 + new Random().nextInt(100)) });
    }
    database.setTransactionSuccessful();
    database.endTransaction();
    System.out.println("事务模式耗时:"+(SystemClock.currentThreadTimeMillis()-startTime)+"毫秒");
    // 关闭数据库释放资源
    database.close();
}


图 1-2 事务执行效率对比

通过如图 1-2 的测试结果我们发现使用事务大大提高了批量处理的效率。

sqlite3 工具的使用

sqlite3 是 Android 内置的操作数据库工具,使用该工具可以直接对 SQLite 数据库进行操作。 操作步骤(如图 1-3):
1、在命令行界面使用 adb shell 命令进入 linux 内核
2、使用 cd 命令进入数据库所在目录(数据库的路径为”/data/data/应用包名/databases/数据库”)
3、使用”sqlite3 数据库名”进入数据库操作模式

图 1-3 sqlite3 使用截图

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值