Android中 Sqlite數(shù)據(jù)庫(kù)使用

概述

Sqlite數(shù)據(jù)庫(kù)是Android系統(tǒng)內(nèi)常用的數(shù)據(jù)存儲(chǔ)的方式之一,還有其他幾種存儲(chǔ)方式:文件存儲(chǔ),SP存儲(chǔ)等。

SQLite是一個(gè)進(jìn)程內(nèi)的輕量級(jí)嵌入式數(shù)據(jù)庫(kù),它的數(shù)據(jù)庫(kù)就是一個(gè)文件,實(shí)現(xiàn)了自給自足、無(wú)服務(wù)器、零配置的、事務(wù)性的SQL數(shù)據(jù)庫(kù)引擎。它是一個(gè)零配置的數(shù)據(jù)庫(kù),這就體現(xiàn)出來(lái)SQLite與其他數(shù)據(jù)庫(kù)的最大的區(qū)別:SQLite不需要在系統(tǒng)中配置,直接可以使用。且SQLite不是一個(gè)獨(dú)立的進(jìn)程,可以按應(yīng)用程序需求進(jìn)行靜態(tài)或動(dòng)態(tài)連接。SQLite可直接訪問(wèn)其存儲(chǔ)文件。

Sqlite具有如下特點(diǎn):

  1. 存儲(chǔ)結(jié)構(gòu)型,關(guān)系型數(shù)據(jù)
  2. 支持SQL語(yǔ)言
  3. 支持事務(wù)處理
  4. 獨(dú)立,無(wú)需服務(wù)進(jìn)程

使用

使用SQLite實(shí)現(xiàn)需要了解SQLiteOpenHelper數(shù)據(jù)庫(kù)工具類。
SQLiteOpenHelper是一個(gè)在Android中使用的Sqlite數(shù)據(jù)庫(kù)輔助操作的工具類,可以用來(lái)管理數(shù)據(jù)庫(kù)操作(增刪改查)以及版本控制。

使用Sqlite數(shù)據(jù)庫(kù)主要包括如下幾個(gè)步驟:

  1. 創(chuàng)建SQLiteOpenHelper的子類,用來(lái)管理數(shù)據(jù)表的創(chuàng)建,數(shù)據(jù)庫(kù)版本控制,根據(jù)需求實(shí)現(xiàn)其中的方法。
  2. 新建SQLiteDBManager數(shù)據(jù)庫(kù)工具類用來(lái)承載數(shù)據(jù)庫(kù)的增刪改查操作。

接下來(lái)對(duì)上述兩個(gè)步驟進(jìn)行簡(jiǎn)單說(shuō)明。

一、 SQliteOpenHelper

首先我們需要?jiǎng)?chuàng)建一個(gè)SQLiteOpenHelper的子類,作為數(shù)據(jù)庫(kù)創(chuàng)建的輔助工具類。在此工具類中有兩個(gè)重要方法:onCreateonUpgrade方法。
onCreate是創(chuàng)建方法,部分表的創(chuàng)建可以在此實(shí)現(xiàn),通過(guò)SQL語(yǔ)句以及execSQL()的方法可以很快的就能夠?qū)崿F(xiàn)。
onUpgrade是用來(lái)控制數(shù)據(jù)庫(kù)升級(jí)的,在此方法中可以控制數(shù)據(jù)庫(kù)版本的變動(dòng)。

升級(jí)方法中需要對(duì)于版本的升級(jí)降級(jí)的每一項(xiàng)操作都要包含到,以免造成錯(cuò)誤。

示例代碼如下:

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語(yǔ)句
        LogUtil.instance.d("onUpgrade,newVersion is $newVersion")
        if (db == null)
            return
        db.beginTransaction()     //加入事務(wù)
        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"
    }
}

上面對(duì)于SQL表的操作加入和事務(wù),使得操作具有原子性和持久性。

除此之外,還需要初始化數(shù)據(jù)庫(kù),也就是創(chuàng)建一個(gè)SQliteOpenHelper對(duì)象,示例如下:

/**
     * 創(chuàng)建數(shù)據(jù)庫(kù)對(duì)象
     */
    fun createDb(version: Int) {
        var sqLiteHelper = DataBaseHelper(
            context,
            "sqlite_test",
            null,
            version,
            null
        )
        sqLiteDB = sqLiteHelper.readableDatabase
        //和read方法一樣都能夠獲得一個(gè)可讀寫(xiě)的數(shù)據(jù)庫(kù)對(duì)象,注意和read的區(qū)別
//        sqLiteDB = sqLiteHelper.writableDatabase
    }

通過(guò)SQliteOpenHelper構(gòu)造函數(shù)聲明數(shù)據(jù)庫(kù)的版本和名稱等信息,然后通過(guò)getreadableDatabasewritableDatabase獲取到數(shù)據(jù)庫(kù)對(duì)象,之后在通過(guò)此數(shù)據(jù)庫(kù)對(duì)象進(jìn)行具體的數(shù)據(jù)表操作。

需要注意的是readableDatabasewritableDatabase的區(qū)別,兩者雖然都能夠獲取到數(shù)據(jù)庫(kù)對(duì)象,但是在當(dāng)數(shù)據(jù)庫(kù)在磁盤(pán)滿了不能寫(xiě)入的情況下采用writableDatabase是會(huì)打開(kāi)失敗報(bào)錯(cuò)的,而采用readableDatabase只是會(huì)以只可讀的方式打開(kāi)數(shù)據(jù)庫(kù),不錯(cuò)直接報(bào)錯(cuò)。

定義具體的數(shù)據(jù)類,示例如下:

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"
    }
}

二、數(shù)據(jù)操作類

在定義了數(shù)據(jù)庫(kù)類之后,接下來(lái)我們就可以定義具體的數(shù)據(jù)表操作了,也就是增刪改查等數(shù)據(jù)操作。
在SQLite中,數(shù)據(jù)操作有兩種方式,一種是直接調(diào)用SQLiteDatabase的方法,另一種是采用執(zhí)行SQL語(yǔ)句的方式。下面對(duì)增刪改查各種操作進(jìn)行逐一說(shuō)明。

1. 增加

增加可以通過(guò)調(diào)用SQLiteDatabaseinsert方法進(jìn)行插入數(shù)據(jù),示例如下:

 /**
     * 使用insert方法添加數(shù)據(jù)
     * @param:插入的數(shù)據(jù)
     */
    fun insert1(person: TablePerson) {
        sqLiteDB?.beginTransaction() ?: return
        try {
            if (checkExistData(person.id)) {
                LogUtil.instance.toast("數(shù)據(jù)已經(jīng)存在", 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("插入數(shù)據(jù)失敗")
        } finally {
            sqLiteDB?.endTransaction()
        }
    }

除此之外,還可以通過(guò)調(diào)用SQL語(yǔ)句的方法實(shí)現(xiàn)

    /**
     * 使用SQL語(yǔ)句添加數(shù)據(jù)
     * @param person:插入的數(shù)據(jù)
     * 注意需要在字符串添加''
     */
    fun insert2(person: TablePerson) {
        sqLiteDB?.beginTransaction() ?: return
        try {
            if (checkExistData(person.id)) {
                LogUtil.instance.toast("數(shù)據(jù)已經(jīng)存在", 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("插入數(shù)據(jù)失敗")
        } finally {
            sqLiteDB?.endTransaction()
        }
    }

通過(guò)SQL語(yǔ)句進(jìn)行操作一般都是去調(diào)用execSQL方法。

2. 更新

更新可以通過(guò)調(diào)用SQLiteDatabaseupdate方法進(jìn)行插入數(shù)據(jù),示例如下:

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

                // a. 創(chuàng)建一個(gè)ContentValues對(duì)象
                var values = ContentValues()
                values.put(TablePerson.NAME_COLUMN, person.name)
                // b. 調(diào)用update方法修改數(shù)據(jù)庫(kù):將id=1 修改成 name = zhangsan
                sqLiteDB?.update(
                    DataBaseHelper.TEST_TABLE_NAME,
                    values,
                    TablePerson.ID_COLUMN + "=?",
                    arrayOf(person.id.toString())
                )
                // 參數(shù)1:表名(String)
                // 參數(shù)2:需修改的ContentValues對(duì)象
                // 參數(shù)3:WHERE表達(dá)式(String),需數(shù)據(jù)更新的行; 若該參數(shù)為 null, 就會(huì)修改所有行;?號(hào)是占位符
                // 參數(shù)4:WHERE選擇語(yǔ)句的參數(shù)(String[]), 逐個(gè)替換 WHERE表達(dá)式中 的“?”占位符;

            } else {
                LogUtil.instance.toast("數(shù)據(jù)不存在", context)
            }
            sqLiteDB?.setTransactionSuccessful()
        } catch (e: Exception) {
            e.printStackTrace()
            LogUtil.instance.d("更新數(shù)據(jù)失敗")
        } finally {
            sqLiteDB?.endTransaction()
        }
    }

當(dāng)然也可以通過(guò)調(diào)用SQL語(yǔ)句進(jìn)行實(shí)現(xiàn):

    /**
     * 使用SQL語(yǔ)句更新數(shù)據(jù)
     * @param:更新的數(shù)據(jù)。
     * 注意字符串添加''
     */
    fun update2(person: TablePerson) {
        sqLiteDB?.beginTransaction() ?: return
        try {
            if (checkExistData(person.id)) {
                // 注:也可采用SQL語(yǔ)句修改
                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("數(shù)據(jù)不存在", context)
            }
            sqLiteDB?.setTransactionSuccessful()
        } catch (e: Exception) {
            e.printStackTrace()
            LogUtil.instance.d("更新數(shù)據(jù)失敗")
        } finally {
            sqLiteDB?.endTransaction()
        }
    }

3. 刪除

更新可以通過(guò)調(diào)用SQLiteDatabasedelete方法進(jìn)行插入數(shù)據(jù),示例如下:

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

當(dāng)然也可以通過(guò)SQL語(yǔ)句實(shí)現(xiàn):

    /**
     * 使用SQL語(yǔ)句刪除數(shù)據(jù)
     * @param:刪除數(shù)據(jù)的ID
     */
    fun delete2(id: Int) {
        sqLiteDB?.beginTransaction() ?: return
        try {
            if (checkExistData(id)) {
                // 注:也可采用SQL語(yǔ)句修改
                var deleteSql =
                    "delete from " + DataBaseHelper.TEST_TABLE_NAME + " where " +
                            TablePerson.ID_COLUMN + " = " + id
                sqLiteDB?.execSQL(deleteSql)
            } else {
                LogUtil.instance.toast("數(shù)據(jù)不存在", context)
            }
            sqLiteDB?.setTransactionSuccessful()
        } catch (e: Exception) {
            e.printStackTrace()
            LogUtil.instance.d("更新數(shù)據(jù)失敗")
        } finally {
            sqLiteDB?.endTransaction()
        }
    }

4. 查詢

由于查詢操作相對(duì)增刪改操作更加復(fù)雜,尤其是在查詢的條件和格式上都比較復(fù)雜,因此使用的SQL語(yǔ)句來(lái)實(shí)現(xiàn)查詢操作,調(diào)用SQLiteDatabaserawQuery或者query方法來(lái)實(shí)現(xiàn)結(jié)果。

query和rawQuery方法更多的是在參數(shù)上的不同,查看源碼可以發(fā)現(xiàn)二者最后調(diào)用的是同一個(gè)方法。

    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()
    }

可以看到查詢的方式主要是游標(biāo)移動(dòng)查詢,游標(biāo)的方法有多種,部分示例如下,大家可以根據(jù)情況自行選擇:

    /**
    //Cursor對(duì)象常用方法如下:
    c.move(int offset); //以當(dāng)前位置為參考,移動(dòng)到指定行
    c.moveToFirst();    //移動(dòng)到第一行
    c.moveToLast();     //移動(dòng)到最后一行
    c.moveToPosition(int position); //移動(dòng)到指定行
    c.moveToPrevious(); //移動(dòng)到前一行
    c.moveToNext();     //移動(dòng)到下一行
    c.isFirst();        //是否指向第一條
    c.isLast();     //是否指向最后一條
    c.isBeforeFirst();  //是否指向第一條之前
    c.isAfterLast();    //是否指向最后一條之后
    c.isNull(int columnIndex);  //指定列是否為空(列基數(shù)為0)
    c.isClosed();       //游標(biāo)是否已關(guān)閉
    c.getCount();       //總數(shù)據(jù)項(xiàng)數(shù)
    c.getPosition();    //返回當(dāng)前游標(biāo)所指向的行數(shù)
    c.getColumnIndex(String columnName);//返回某列名對(duì)應(yīng)的列索引值
    c.getString(int columnIndex);   //返回當(dāng)前行指定列的值

    // 方法說(shuō)明
    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);

    // 參數(shù)說(shuō)明
    // table:要操作的表
    // columns:查詢的列所有名稱集
    // selection:WHERE之后的條件語(yǔ)句,可以使用占位符
    // groupBy:指定分組的列名
    // having指定分組條件,配合groupBy使用
    // orderBy指定排序的列名
    // limit指定分頁(yè)參數(shù)
    // distinct可以指定“true”或“false”表示要不要過(guò)濾重復(fù)值

     */

其他

示例Demo

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • SQLite是一種嵌入式的數(shù)據(jù)庫(kù)引擎,最后是以文件的形式保存數(shù)據(jù)的,專門(mén)適用于資源有限的設(shè)備上進(jìn)行適量的數(shù)據(jù)存儲(chǔ),...
    李俊的博客閱讀 3,604評(píng)論 0 8
  • SQLite 是一款輕量級(jí)的關(guān)系型數(shù)據(jù)庫(kù),它的運(yùn)算速度非常快, 占用資源很少,通常只需幾百 K 的內(nèi)存就足夠了,因...
    deniro閱讀 762評(píng)論 1 9
  • 前言 在Android開(kāi)發(fā)過(guò)程中,對(duì)于數(shù)據(jù)的存儲(chǔ),我們或多或少的都會(huì)使用到數(shù)據(jù)庫(kù)相關(guān)的操作,所以在此小小的總結(jié)一下...
    Xuelong_li閱讀 729評(píng)論 0 6
  • SQLite介紹 SQLite是一款輕量級(jí)的關(guān)系型數(shù)據(jù)庫(kù),它的運(yùn)算速度非常快,占用資源很少,通常只需要幾百K的內(nèi)存...
    pisfans閱讀 181評(píng)論 0 0
  • 推薦指數(shù): 6.0 書(shū)籍主旨關(guān)鍵詞:特權(quán)、焦點(diǎn)、注意力、語(yǔ)言聯(lián)想、情景聯(lián)想 觀點(diǎn): 1.統(tǒng)計(jì)學(xué)現(xiàn)在叫數(shù)據(jù)分析,社會(huì)...
    Jenaral閱讀 5,742評(píng)論 0 5