SQLite 數(shù)據(jù)庫使用

概述

在項(xiàng)目的開發(fā)過程中,有很多功能都需要我們將數(shù)據(jù)保存到我們的手機(jī)本地來提升app的性能,常見的有圖片緩存、消息的離線緩存等;
Android端常見的本地?cái)?shù)據(jù)緩存方式有:

  1. SharedPreference:緩存輕量級的 key-value 類型的數(shù)據(jù),例如:賬號、密碼等;
  2. File:用來存儲文件,例如:圖片,音樂等;
  3. SQLite:用來存儲大量復(fù)雜的關(guān)系型數(shù)據(jù);

我們知道現(xiàn)在的app都是數(shù)據(jù)量比較大的,例如我們每天使用的qq,少的來說也有幾百條消息記錄,多的有可能是上萬條的消息數(shù)據(jù),如果我們使用 SharedPreference 或者 File 來存儲顯然是不合適的,這時(shí)候就應(yīng)該輪到SQLite數(shù)據(jù)庫上場了;


@A@

本片文章著重講的是如何使用,關(guān)于 SQLite 的概念大家可以自己去找資料;

關(guān)于SQLiteOpenHelper的使用

Android 官方幫我們封裝了一個(gè)SQLiteOpenHelper類來幫助我們操作數(shù)據(jù)庫;我們只需要寫一個(gè)類繼承它,重寫抽象方法即可;

public class DbOpenHelper extends SQLiteOpenHelper {

    public static DbOpenHelper mInstance;

    private DbOpenHelper() {
        super(AppApplication.mContext, getUserDatabaseName(), null, Constant.DATABASE_VERSION);
    }

    /**
     * @param context 我們可以使用ApplicationContext,因此我們在設(shè)計(jì)單例的時(shí)候可以設(shè)置成無參
     * @param name    創(chuàng)建的數(shù)據(jù)庫的名稱
     * @param factory 游標(biāo)工廠,直接傳入null就好
     * @param version 創(chuàng)建的數(shù)據(jù)庫版本 >= 1
     */
    private DbOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
        super(context, name, factory, version);
    }


    public static DbOpenHelper getInstance() {
        if (mInstance == null) {
            synchronized (DbOpenHelper.class) {
                if (mInstance == null) {
                    mInstance = new DbOpenHelper();
                }
            }
        }
        return mInstance;
    }

    /**
     * 當(dāng)數(shù)據(jù)庫創(chuàng)建(db文件)的時(shí)候調(diào)用(此處我們執(zhí)行當(dāng)前版本所有的表的創(chuàng)建語句)
     *
     * @param db 數(shù)據(jù)庫對象
     */
    @Override
    public void onCreate(SQLiteDatabase db) {
        Log.e("TAG", "-----onCreate-----");
    }

    /**
     * 當(dāng)數(shù)據(jù)庫有版本更新的時(shí)候調(diào)用,在這里我們根據(jù)不同的版本對數(shù)據(jù)庫進(jìn)行相關(guān)修改
     *
     * @param db         數(shù)據(jù)庫對象
     * @param oldVersion 數(shù)據(jù)庫舊版本
     * @param newVersion 數(shù)據(jù)庫更新
     */
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        Log.e("TAG", "-----onUpgrade-----");
    }

    /**
     * 拼接生成不同的db文件(如果是IM項(xiàng)目,不同的賬號登錄應(yīng)該對應(yīng)不同的db文件)
     *
     * @return
     */
    private static String getUserDatabaseName() {
        return Constant.DATABASE_NAME + "_demo.db";
    }
    
}

相關(guān)方法的解析大家可以查看注釋,還是比較容易理解的,這里我們需要注意的是默認(rèn)的數(shù)據(jù)庫db文件保存的位置為 /data/data/'項(xiàng)目包名'/databases/***.db,如果使用模擬器測試,最好將模擬器版本控制在5.0及以下,這樣可以直接查看文件,否則需要自己修改權(quán)限;

DbManager 管理/執(zhí)行 sql 語句

在打開了數(shù)據(jù)庫后,通常我們會再建立一個(gè)數(shù)據(jù)庫管理工具類 DbManager,來管理和執(zhí)行我們的業(yè)務(wù)相關(guān)的SQL,這樣有助于我們管理項(xiàng)目,同樣我們可以將其設(shè)置為單例模式,我們在DbManager類中,通過我們自己定義的DbOpenHelper類,調(diào)用getWritableDatabase()或者getReadableDatabase()方法,拿到數(shù)據(jù)庫讀寫操作的SQLiteDatabase對象來執(zhí)行SQL語句,個(gè)人比較推薦大家使用sql語句,DbManager 類里面就是一些數(shù)據(jù)的增刪改查的方法,這里就不貼代碼了,在文章的末尾會給出項(xiàng)目的github地址;
還有一點(diǎn)就是數(shù)據(jù)庫的名稱、字段名稱在sql語句中出現(xiàn)的頻率非常的高,這里推薦大家給不同的表都建立一個(gè) Dao 類,將 數(shù)據(jù)庫的表名稱,字段名稱寫成靜態(tài)成員變量的形式,這樣可以避免我們在寫 sql 語句的時(shí)候發(fā)生數(shù)據(jù)庫表名稱、字段名稱拼寫錯(cuò)誤的問題,同時(shí)我們可以在此類里面寫入對應(yīng)表的增刪改查操作(實(shí)際還是引用DbManager類里面的方法),在具體的業(yè)務(wù)的地方,直接調(diào)用此對象,這樣也可以讓我們的代碼更加明確,例如:

public class UserDao {

    // 將數(shù)據(jù)庫表中的相關(guān)字段名稱定義到這里,防止拼寫錯(cuò)誤
    public static final String TABLE_NAME = "users";

    public static final String COLUMN_NAME_ID = "id";
    public static final String COLUMN_NAME_USER = "user_name";
    public static final String COLUMN_NAME_PASSWORD = "password";
    public static final String COLUMN_NAME_EMAIL = "email";

    public void insert(User user) {
        DbManager.getInstance().insertUser(user);
    }

    public ArrayList<User> selectAll() {
        return DbManager.getInstance().selectAllUsers();
    }

    public void updateByName(User user) {
        DbManager.getInstance().updateUserByName(user);
    }

    public void deleteByUserName(String userName) {
        DbManager.getInstance().deleteUserByName(userName);
    }

}

關(guān)于db文件

類似IM之類的app,通常表的結(jié)構(gòu)是已經(jīng)擬定好了的,用于區(qū)分不同賬號的最好的方式就是根據(jù)登錄的用戶,創(chuàng)建單獨(dú)的db文件,因?yàn)?code>SQLiteOpenHelper 類打開的是一個(gè)db文件,在用戶登錄的時(shí)候判斷創(chuàng)建/打開具體的db文件:

db文件

具體的寫法可以參考上面類中的 getUserDatabaseName() 方法;

關(guān)于數(shù)據(jù)庫的版本更新

隨著業(yè)務(wù)改變,應(yīng)用的版本也在更新,如果在業(yè)務(wù)更新的同時(shí),數(shù)據(jù)庫表的數(shù)據(jù)結(jié)構(gòu)發(fā)生了修改,或者增加了新表(通常只有增加表或字段,基本不會刪除表和字段),我們需要將我們的數(shù)據(jù)庫的版本往上增加,此時(shí):

  1. 新用戶:調(diào)用 onCreate 方法,在此方法內(nèi)完成數(shù)據(jù)庫表的創(chuàng)建;
  2. 舊版本用戶: 調(diào)用 onUpgrade 方法,在此方法內(nèi)判斷舊版的數(shù)據(jù)庫版本,然后逐版本的更新數(shù)據(jù)庫中的表,直至更新到當(dāng)前新安裝的數(shù)據(jù)庫的版本;


    @A@
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    Log.e("TAG", "-----onUpgrade-----");

    if (oldVersion < 2) {
        // 刪除原來的表,新建數(shù)據(jù)庫表(基本不會有此操作)
        String sql = "drop table user";
        db.execSQL(sql);
        db.execSQL(USER_CREATE_TABLE);
    }
    if (oldVersion < 3) {
        // 增加列
        Log.e("TAG", "-----------onUpgrade--------- 增加 email 列");
        String sql = "alter table " + UserDao.TABLE_NAME + " add " + UserDao.COLUMN_NAME_EMAIL + " text";
        db.execSQL(sql);
    }

    if (oldVersion < 4) {
        // 刪除列(基本不會有此操作)
        // SQLite不支持刪除列操作,需要進(jìn)行以下操作來完成
        Log.e("TAG", "-----------onUpgrade--------- 刪除 password 列");
        // 1.創(chuàng)建一張臨時(shí)表
        String sql = "create table temp as select " + UserDao.COLUMN_NAME_ID + ", " + UserDao.COLUMN_NAME_USER + ", " + UserDao.COLUMN_NAME_EMAIL + " from " + UserDao.TABLE_NAME + " where 1 = 1";
        db.execSQL(sql);
        // 2.刪除原來的表
        sql = "drop table " + UserDao.TABLE_NAME;
        db.execSQL(sql);
        // 3.修改臨時(shí)表的名稱
        sql = "alter table temp rename to " + UserDao.TABLE_NAME;
        db.execSQL(sql);

    }

    if (oldVersion < 5) {
        // 增加表
        Log.e("TAG", "-----------onUpgrade--------- 增加表 performance");
        db.execSQL(PERFORMANCE_CREATE_TABLE);
        String sql = "insert into " + PerformanceDao.TABLE_NAME + "(" + PerformanceDao.COLUMN_NAME_USER_ID + ", " + PerformanceDao.COLUMN_NAME_SALARY + ") values(1, 20.00)";
        db.execSQL(sql);
    }

}

總結(jié)

本案例主要還是偏向于SQLite數(shù)據(jù)庫的使用而不是原理解析,主要是想先知其然,然后知其所以然,如果想要深入了解的,大家可以google下,這方面的資料還是比較多的;
其實(shí)Android中SQLite用起來還是比較簡單的,不需要向Java中其它數(shù)據(jù)庫連接使用jdbc一樣,直接通過 SQLiteOpenHelper 類就可以幫助我們很快速的進(jìn)行操作數(shù)據(jù)庫;

項(xiàng)目的github地址

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容