Android中 Sqlite数据库使用

概述

Sqlite数据库是Android系统内常用的数据存储的方式之一,还有其他几种存储方式:文件存储,SP存储等。

SQLite是一个进程内的轻量级嵌入式数据库,它的数据库就是一个文件,实现了自给自足、无服务器、零配置的、事务性的SQL数据库引擎。它是一个零配置的数据库,这就体现出来SQLite与其他数据库的最大的区别:SQLite不需要在系统中配置,直接可以使用。且SQLite不是一个独立的进程,可以按应用程序需求进行静态或动态连接。SQLite可直接访问其存储文件。

Sqlite具有如下特点:

  1. 存储结构型,关系型数据
  2. 支持SQL语言
  3. 支持事务处理
  4. 独立,无需服务进程

使用

使用SQLite实现需要了解SQLiteOpenHelper数据库工具类。
SQLiteOpenHelper是一个在Android中使用的Sqlite数据库辅助操作的工具类,可以用来管理数据库操作(增删改查)以及版本控制。

使用Sqlite数据库主要包括如下几个步骤:

  1. 创建SQLiteOpenHelper的子类,用来管理数据表的创建,数据库版本控制,根据需求实现其中的方法。
  2. 新建SQLiteDBManager数据库工具类用来承载数据库的增删改查操作。

接下来对上述两个步骤进行简单说明。

一、 SQliteOpenHelper

首先我们需要创建一个SQLiteOpenHelper的子类,作为数据库创建的辅助工具类。在此工具类中有两个重要方法:onCreateonUpgrade方法。
onCreate是创建方法,部分表的创建可以在此实现,通过SQL语句以及execSQL()的方法可以很快的就能够实现。
onUpgrade是用来控制数据库升级的,在此方法中可以控制数据库版本的变动。

升级方法中需要对于版本的升级降级的每一项操作都要包含到,以免造成错误。

示例代码如下:

class DataBaseHelper(
    context: Context?, name: String?, factory: SQLiteDatabase.CursorFactory?,
    version: Int, errorHandler: DatabaseErrorHandler?
) : SQLiteOpenHelper(context, name, factory, version, errorHandler) {

    override fun onCreate(db: SQLiteDatabase?) {
        var sqlCreate =
            "create table " + TEST_TABLE_NAME + "(" + TablePerson.ID_COLUMN + " integer primary key autoincrement," +
                    TablePerson.NAME_COLUMN + " varchar(64))"
        db?.execSQL(sqlCreate)
    }

    override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {
        // 使用 SQL的ALTER语句
        LogUtil.instance.d("onUpgrade,newVersion is $newVersion")
        if (db == null)
            return
        db.beginTransaction()     //加入事务
        try {
            for (j in oldVersion..newVersion) {
                when (j) {
                    2 -> {
                        var sql =
                            "alter table $TEST_TABLE_NAME add other varchar(64)"
                        LogUtil.instance.d(sql)
                        db?.execSQL(sql)
                    }
                    3 -> {
                    }
                    else -> {
                    }
                }
            }
            db.setTransactionSuccessful()
        } catch (e: Exception) {
            e.printStackTrace()
            LogUtil.instance.d("Monicat:SQLiteDatabase upgrade failed.")
        } finally {
            db.endTransaction()
        }

    }

    companion object {
        const val TEST_TABLE_NAME = "person"
    }
}

上面对于SQL表的操作加入和事务,使得操作具有原子性和持久性。

除此之外,还需要初始化数据库,也就是创建一个SQliteOpenHelper对象,示例如下:

/**
     * 创建数据库对象
     */
    fun createDb(version: Int) {
        var sqLiteHelper = DataBaseHelper(
            context,
            "sqlite_test",
            null,
            version,
            null
        )
        sqLiteDB = sqLiteHelper.readableDatabase
        //和read方法一样都能够获得一个可读写的数据库对象,注意和read的区别
//        sqLiteDB = sqLiteHelper.writableDatabase
    }

通过SQliteOpenHelper构造函数声明数据库的版本和名称等信息,然后通过getreadableDatabasewritableDatabase获取到数据库对象,之后在通过此数据库对象进行具体的数据表操作。

需要注意的是readableDatabasewritableDatabase的区别,两者虽然都能够获取到数据库对象,但是在当数据库在磁盘满了不能写入的情况下采用writableDatabase是会打开失败报错的,而采用readableDatabase只是会以只可读的方式打开数据库,不错直接报错。

定义具体的数据类,示例如下:

package com.example.demowork1.database.sqlite

class TablePerson(
    var id: Int,
    var name: String
) {
    companion object {
        const val ID_COLUMN = "id"
        const val NAME_COLUMN = "name"
    }
}
二、数据操作类

在定义了数据库类之后,接下来我们就可以定义具体的数据表操作了,也就是增删改查等数据操作。
在SQLite中,数据操作有两种方式,一种是直接调用SQLiteDatabase的方法,另一种是采用执行SQL语句的方式。下面对增删改查各种操作进行逐一说明。

1. 增加

增加可以通过调用SQLiteDatabaseinsert方法进行插入数据,示例如下:

 /**
     * 使用insert方法添加数据
     * @param:插入的数据
     */
    fun insert1(person: TablePerson) {
        sqLiteDB?.beginTransaction() ?: return
        try {
            if (checkExistData(person.id)) {
                LogUtil.instance.toast("数据已经存在", context)
            } else {
                var values = ContentValues()
                values.put(TablePerson.ID_COLUMN, person.id)
                values.put(TablePerson.NAME_COLUMN, person.name)
                sqLiteDB?.insert(
                    DataBaseHelper.TEST_TABLE_NAME, null, values)
            }
            sqLiteDB?.setTransactionSuccessful()
        } catch (e: Exception) {
            e.printStackTrace()
            LogUtil.instance.d("插入数据失败")
        } finally {
            sqLiteDB?.endTransaction()
        }
    }

除此之外,还可以通过调用SQL语句的方法实现

    /**
     * 使用SQL语句添加数据
     * @param person:插入的数据
     * 注意需要在字符串添加''
     */
    fun insert2(person: TablePerson) {
        sqLiteDB?.beginTransaction() ?: return
        try {
            if (checkExistData(person.id)) {
                LogUtil.instance.toast("数据已经存在", context)
            } else {
                var insertSql =
                    "insert into " + DataBaseHelper.TEST_TABLE_NAME + " (" + TablePerson.ID_COLUMN + " , " +
                            TablePerson.NAME_COLUMN + ") values (" + person.id + " , '" + person.name + "')"
                sqLiteDB?.execSQL(insertSql)
            }
            sqLiteDB?.setTransactionSuccessful()
        } catch (e: Exception) {
            e.printStackTrace()
            LogUtil.instance.d("插入数据失败")
        } finally {
            sqLiteDB?.endTransaction()
        }
    }

通过SQL语句进行操作一般都是去调用execSQL方法。

2. 更新

更新可以通过调用SQLiteDatabaseupdate方法进行插入数据,示例如下:

 /**
     * 使用update方法更新数据
     * @param:更新的数据
     */
    fun update1(person: TablePerson) {
        sqLiteDB?.beginTransaction() ?: return
        try {
            if (checkExistData(person.id)) {

                // a. 创建一个ContentValues对象
                var values = ContentValues()
                values.put(TablePerson.NAME_COLUMN, person.name)
                // b. 调用update方法修改数据库:将id=1 修改成 name = zhangsan
                sqLiteDB?.update(
                    DataBaseHelper.TEST_TABLE_NAME,
                    values,
                    TablePerson.ID_COLUMN + "=?",
                    arrayOf(person.id.toString())
                )
                // 参数1:表名(String)
                // 参数2:需修改的ContentValues对象
                // 参数3:WHERE表达式(String),需数据更新的行; 若该参数为 null, 就会修改所有行;?号是占位符
                // 参数4:WHERE选择语句的参数(String[]), 逐个替换 WHERE表达式中 的“?”占位符;

            } else {
                LogUtil.instance.toast("数据不存在", context)
            }
            sqLiteDB?.setTransactionSuccessful()
        } catch (e: Exception) {
            e.printStackTrace()
            LogUtil.instance.d("更新数据失败")
        } finally {
            sqLiteDB?.endTransaction()
        }
    }

当然也可以通过调用SQL语句进行实现:

    /**
     * 使用SQL语句更新数据
     * @param:更新的数据。
     * 注意字符串添加''
     */
    fun update2(person: TablePerson) {
        sqLiteDB?.beginTransaction() ?: return
        try {
            if (checkExistData(person.id)) {
                // 注:也可采用SQL语句修改
                var updateSql =
                    "update " + DataBaseHelper.TEST_TABLE_NAME + " set " + TablePerson.NAME_COLUMN +
                            " = '" + person.name + "' where " + TablePerson.ID_COLUMN + " = " + person.id
                sqLiteDB?.execSQL(updateSql)
            } else {
                LogUtil.instance.toast("数据不存在", context)
            }
            sqLiteDB?.setTransactionSuccessful()
        } catch (e: Exception) {
            e.printStackTrace()
            LogUtil.instance.d("更新数据失败")
        } finally {
            sqLiteDB?.endTransaction()
        }
    }
3. 删除

更新可以通过调用SQLiteDatabasedelete方法进行插入数据,示例如下:

 /**
     * 使用delete方法删除数据
     * @param:删除数据的ID
     */
    fun delete1(id: Int) {
        sqLiteDB?.beginTransaction() ?: return
        try {
            if (checkExistData(id)) {
                sqLiteDB?.delete(          //参数和update方法相似
                    DataBaseHelper.TEST_TABLE_NAME, TablePerson.ID_COLUMN + "=?",
                    arrayOf(id.toString())
                )
            } else {
                LogUtil.instance.toast("数据不存在", context)
            }
            sqLiteDB?.setTransactionSuccessful()
        } catch (e: Exception) {
            e.printStackTrace()
            LogUtil.instance.d("更新数据失败")
        } finally {
            sqLiteDB?.endTransaction()
        }
    }

当然也可以通过SQL语句实现:

    /**
     * 使用SQL语句删除数据
     * @param:删除数据的ID
     */
    fun delete2(id: Int) {
        sqLiteDB?.beginTransaction() ?: return
        try {
            if (checkExistData(id)) {
                // 注:也可采用SQL语句修改
                var deleteSql =
                    "delete from " + DataBaseHelper.TEST_TABLE_NAME + " where " +
                            TablePerson.ID_COLUMN + " = " + id
                sqLiteDB?.execSQL(deleteSql)
            } else {
                LogUtil.instance.toast("数据不存在", context)
            }
            sqLiteDB?.setTransactionSuccessful()
        } catch (e: Exception) {
            e.printStackTrace()
            LogUtil.instance.d("更新数据失败")
        } finally {
            sqLiteDB?.endTransaction()
        }
    }
4. 查询

由于查询操作相对增删改操作更加复杂,尤其是在查询的条件和格式上都比较复杂,因此使用的SQL语句来实现查询操作,调用SQLiteDatabaserawQuery或者query方法来实现结果。

query和rawQuery方法更多的是在参数上的不同,查看源码可以发现二者最后调用的是同一个方法。

    fun queryTest1(id: Int) {
        val result =
            sqLiteDB?.rawQuery("select * from person where id>?", arrayOf(id.toString())) ?: return

//        var result = sqLiteDB?.query(DataBaseHelper.TEST_TABLE_NAME, arrayOf(TablePerson.ID_COLUMN, TablePerson.NAME_COLUMN),
//                "id>?", arrayOf(id.toString()), null, null, null) ?: return
        result.moveToFirst()
        while (!result.isAfterLast) {
            var mId: Int = result.getInt(0)
            var mName: String = result.getString(1)
            LogUtil.instance.d("id=$mId   name$mName")
            // do something useful with these
            result.moveToNext()
        }
        result.close()
    }

可以看到查询的方式主要是游标移动查询,游标的方法有多种,部分示例如下,大家可以根据情况自行选择:

    /**
    //Cursor对象常用方法如下:
    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);   //返回当前行指定列的值

    // 方法说明
    db.query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy);
    db.query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit);
    db.query(String distinct, String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit);

    // 参数说明
    // table:要操作的表
    // columns:查询的列所有名称集
    // selection:WHERE之后的条件语句,可以使用占位符
    // groupBy:指定分组的列名
    // having指定分组条件,配合groupBy使用
    // orderBy指定排序的列名
    // limit指定分页参数
    // distinct可以指定“true”或“false”表示要不要过滤重复值

     */

其他

示例Demo

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值