一篇技術(shù)好文之Android數(shù)據(jù)庫 SQite全解析

數(shù)據(jù)庫SQLite.jpg

這篇文章是數(shù)據(jù)庫系列篇文章的第一篇佃声,主要講Android Sqlite數(shù)據(jù)庫存儲菲嘴,后面陸續(xù)出GreenDao,LitePal, Realm,wcdb的文章蚌吸,一如既往锈拨,如果遇到任何關(guān)于Android中SQLite的問題,都可以直接在我的文章底部留言羹唠,或者直接在我的公眾號aserbao留言奕枢,文章會持續(xù)更新,希望這篇文章能為大家提供到幫助佩微!如果覺得文章對你有用缝彬,就幫忙點(diǎn)個贊,若覺得文章寫得不好之處望指出哺眯,必將加以修正跌造!


qrcode_for_gh_2886db5aaf83_258.jpg

這篇文章主要講SQlite數(shù)據(jù)庫存儲,從數(shù)據(jù)庫建表到數(shù)據(jù)庫的增刪改查操作族购,再到數(shù)據(jù)庫升級操作壳贪,最后是文章總結(jié)及參考鏈接

SQlite

1. 創(chuàng)建數(shù)據(jù)庫

Android中使用SQlite,需要自己創(chuàng)建庫寝杖,建表违施,添加數(shù)據(jù)!好在Android中提供了SQLiteOpenHelper類來幫助創(chuàng)建使用數(shù)據(jù)庫瑟幕,我們只需要繼承這個類就可以實(shí)現(xiàn)數(shù)據(jù)庫的創(chuàng)建和對數(shù)據(jù)的操作了磕蒲!Android 中創(chuàng)建數(shù)據(jù)庫需要通過如下幾部:

  1. 創(chuàng)建一個類繼承SQLiteOpenHelper留潦,需要實(shí)現(xiàn)其三個方法:
    • 構(gòu)造方法:需要給SQLiteOpenHelper傳遞四個參數(shù):(上下文,數(shù)據(jù)庫名辣往,游標(biāo)工廠(通常為null)兔院,當(dāng)前數(shù)據(jù)庫版本號);
    • onCreate(): 表的創(chuàng)建站削,初始化操作
    • onUpgrade(): 表升級
    • 還有:onDowngrade(): 表降級,onOpen:每次打開數(shù)據(jù)庫坊萝,onBeforeDelete:
public class ThingManagerDBOpenHelper extends SQLiteOpenHelper {
    public static final String DB_NAME = "mysql.db";
    private static final int VERSION = 1;
    public ThingManagerDBOpenHelper(Context context) {
        super(context, DB_NAME, null, VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL("CREATE TABLE IF NOT EXISTS "
                + ThingDBController.TABLE_NAME
                + String.format(
                "("
                        + "%s INTEGER PRIMARY KEY AUTOINCREMENT, "
                        + "%s VARCHAR, "
                        + "%s INTEGER"
                        +")"
                , ThingManagerDBModel.ID
                , ThingManagerDBModel.MESSAGE
                , ThingManagerDBModel.TIME
        )) ;
    }


    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
       ……
    }
 
}

說下SQlite的數(shù)據(jù)類型 :

作用
NULL: 這個值為空值
VARCHAR(n): 長度不固定且其最大長度為 n 的字串,n不能超過 4000许起。
CHAR(n): 長度固定為n的字串十偶,n不能超過 254。
INTEGER: 值被標(biāo)識為整數(shù),依據(jù)值的大小可以依次被存儲為1,2,3,4,5,6,7,8.
REAL: 所有值都是浮動的數(shù)值,被存儲為8字節(jié)的IEEE浮動標(biāo)記序號.
TEXT: 值為文本字符串,使用數(shù)據(jù)庫編碼存儲(TUTF-8, UTF-16BE or UTF-16-LE).
BLOB: 值是BLOB數(shù)據(jù)塊园细,以輸入的數(shù)據(jù)格式進(jìn)行存儲惦积。如何輸入就如何存儲,不改 變格式。
DATA: 包含了 年份猛频、月份狮崩、日期。
TIME: 包含了 小時鹿寻、分鐘厉亏、秒。

2. 創(chuàng)建一個數(shù)據(jù)庫存儲對象

public final class ThingManagerDBModel {
    public static final String TABLE_NAME = "mysql_thing";
    public static final String ID = "_id";
    public static final String MESSAGE = "message";
    public static final String TIME = "time";

    int id;
    String message;
    long time;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public long getTime() {
        return time;
    }

    public void setTime(long time) {
        this.time = time;
    }

    public ContentValues toContentValues(){
        ContentValues cv = new ContentValues();
        cv.put(MESSAGE, message);
        cv.put(TIME, time);
        return cv;
    }
}

3. 創(chuàng)建一個數(shù)據(jù)庫控制器實(shí)現(xiàn)增刪改查

1. 增

  1. 使用Android APi來實(shí)現(xiàn)增加數(shù)據(jù)
 public boolean insertApi(int id, String message, long time){
        ThingManagerDBModel dbModel = new ThingManagerDBModel();
        if(id >= 0) {
            dbModel.id = id;
        }
        dbModel.message = message;
        dbModel.time = time;
        final boolean success = db.insert(TABLE_NAME, null, dbModel.toContentValues()) != -1;
        dbClose();
        return success;
    }
  1. 使用Sql語句實(shí)現(xiàn)增加數(shù)據(jù)
 public void insertRaw(String message, long time){
        String sql = " insert into " + TABLE_NAME + "(message,time) values(?,?)";
        Object[] args = {message,time};
        db.execSQL(sql,args);
        dbClose();
    }

2. 刪

  1. 使用Api
  public boolean deleteApi(String whereClause,String[] whereArgs){
        boolean sucess = db.delete(TABLE_NAME, whereClause,whereArgs) != -1;
        dbClose();
        return sucess;
    }
  1. 使用Sql語句
 public void deleteRaw(String message){
        String sql = "delete from "+TABLE_NAME + " where message = ?";
        Object[] args = {message};
        db.execSQL(sql,args);
        dbClose();
    }

3. 改

  1. 使用api
public boolean updateApi(int id,String message,long time){
        ThingManagerDBModel dbModel = new ThingManagerDBModel();
        if(id >= 0) {
            dbModel.id = id;
        }
        dbModel.message = message;
        dbModel.time = time;
        boolean success = db.update(TABLE_NAME, dbModel.toContentValues(), "_id = ?", new String[]{String.valueOf(id)}) != -1;
        dbClose();
        return success;
    }
  1. 使用Sql條件修改
public void updateRaw(int id,String message,long time){
        String sql = "update "+TABLE_NAME + " set message = ?,time = ? where _id = ?";
        Object[] args = {message,time,id};
        db.execSQL(sql,args);
        dbClose();
    }

4. 查

  1. 使用Api
/**
     * @param cloums 要查詢的字段
     * @param selection 查詢條件
     * @param selectionArgs 填充查詢條件的值
     * @return
     */
    public List<Thing> queryApi(String[] cloums,String selection,String[]  selectionArgs){
        try {
            Cursor c = db.query(TABLE_NAME, cloums, selection, selectionArgs, null, null, null);
            ArrayList<Thing> arrayList = new ArrayList<>();
            if (!c.moveToLast()) {
                return arrayList;
            }
            do {
                Thing model = new Thing();
                model.setId(c.getInt(c.getColumnIndexOrThrow(ThingManagerDBModel.ID)));
                model.setTime(c.getLong(c.getColumnIndexOrThrow(ThingManagerDBModel.TIME)));
                model.setMessage(c.getString(c.getColumnIndexOrThrow(ThingManagerDBModel.MESSAGE)));
                arrayList.add(model);
            } while (c.moveToPrevious());
            c.close();
            return arrayList;
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            dbClose();
        }

        return new ArrayList<>();
    }

  1. 使用sql條件
 public List<Thing> queryRawById(String  id){
    //cursor獲取的一定是在這里申明的查詢條件值
        String sql = "select _id,message,time from "+TABLE_NAME + " where _id = ?";
        Cursor cursor = db.rawQuery(sql, new String[]{id});
        ArrayList<Thing> arrayList = new ArrayList<>();
        if (!cursor.moveToLast()) {
            return arrayList;
        }
        do {
            Thing model = new Thing();
            model.setId(cursor.getInt(cursor.getColumnIndex(ThingManagerDBModel.ID)));
            model.setTime(cursor.getLong(cursor.getColumnIndex(ThingManagerDBModel.TIME)));
           model.setMessage(cursor.getString(cursor.getColumnIndexOrThrow(ThingManagerDBModel.MESSAGE)));
            arrayList.add(model);
        } while (cursor.moveToPrevious());
        cursor.close();
        dbClose();
        return arrayList;
    }

4. 數(shù)據(jù)庫的升級

在開發(fā)的過程中烈和,我們避免不了需要修改數(shù)據(jù)庫結(jié)構(gòu)爱只,添加字段或者刪除字段!我們通過增加傳遞給SQLiteOpenHelper的版本值招刹,得到onUpgrade方法的回調(diào)來實(shí)現(xiàn)對數(shù)據(jù)庫的操作來進(jìn)行升級恬试。這里需要注意的是,如果用戶安裝版本1之后直接跳裝版本3疯暑,這時候我們就需要在onUpgrade方法中通過oldVersion來進(jìn)行每一個版本的逐漸升級训柴,方法如下:


public class ThingManagerDBOpenHelper extends SQLiteOpenHelper {
    public static final String DB_NAME = "mysql.db";
    private static final int VERSION = 3;
    ……
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        switch (oldVersion){
            case 1:
                upToDbVersion2(db);
            case 2:
                upToDbVersion3(db);
            default:
              break;
        }
    }
    public void upToDbVersion2(SQLiteDatabase db){
        db.execSQL("ALTER TABLE " + ThingDBController.TABLE_NAME + " ADD COLUMN add_user_name text");
    }

    public void upToDbVersion3(SQLiteDatabase db) {
        ContentValues values = new ContentValues();
        values.put("message", "版本升級后的數(shù)據(jù)");
        db.update(ThingDBController.TABLE_NAME, values, null, null);
    }
}

問題

查詢問題

Cursor只會擁有你查詢的數(shù)據(jù),如果在查詢條件里面沒有申請妇拯,Cursor里面就不會包含這個值幻馁,就會出現(xiàn)如下異常:
錯誤寫法:

 String sql = "select message,time from "+TABLE_NAME + " where _id = ?";//條件里面沒有申請查詢_id的值
 ……something……
 model.setId(cursor.getInt(cursor.getColumnIndex(ThingManagerDBModel.ID)));//在這里提取會報異常

正確寫法:

 String sql = "select  _id,message,time from "+TABLE_NAME + " where _id = ?";//條件里面沒有申請查詢_id的值
 ……something……
 model.setId(cursor.getInt(cursor.getColumnIndex(ThingManagerDBModel.ID)));//這里進(jìn)行id值的提取

異常:

  java.lang.IllegalStateException: Couldn't read row 0, col -1 from CursorWindow.  Make sure the Cursor is initialized correctly before accessing data from it.
        at android.database.CursorWindow.nativeGetLong(Native Method)
        at android.database.CursorWindow.getLong(CursorWindow.java:513)
        at android.database.CursorWindow.getInt(CursorWindow.java:580)
        at android.database.AbstractWindowedCursor.getInt(AbstractWindowedCursor.java:69)
        at com.aserbao.aserbaosandroid.functions.database.mySql.beans.ThingDBController.queryRawById(ThingDBController.java:109)
        at com.aserbao.aserbaosandroid.functions.database.mySql.MySqlActivity.queryData(MySqlActivity.java:70)
        at com.aserbao.aserbaosandroid.functions.database.base.DataBaseBaseActivity.onViewClicked(DataBaseBaseActivity.java:85)
        at com.aserbao.aserbaosandroid.functions.database.base.DataBaseBaseActivity_ViewBinding$2.doClick(DataBaseBaseActivity_ViewBinding.java:48)
        at butterknife.internal.DebouncingOnClickListener.onClick(DebouncingOnClickListener.java:22)
        at android.view.View.performClick(View.java:6291)
        at android.view.View$PerformClick.run(View.java:24931)
        at android.os.Handler.handleCallback(Handler.java:808)
        at android.os.Handler.dispatchMessage(Handler.java:101)
        at android.os.Looper.loop(Looper.java:166)
        at android.app.ActivityThread.main(ActivityThread.java:7425)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:245)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:921)

參考鏈接

  1. Android 開發(fā)中使用 SQLite 數(shù)據(jù)庫
  2. Android數(shù)據(jù)庫Sqlite的基本用法及升級策略
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市越锈,隨后出現(xiàn)的幾起案子仗嗦,更是在濱河造成了極大的恐慌,老刑警劉巖甘凭,帶你破解...
    沈念sama閱讀 212,816評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件稀拐,死亡現(xiàn)場離奇詭異,居然都是意外死亡丹弱,警方通過查閱死者的電腦和手機(jī)德撬,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,729評論 3 385
  • 文/潘曉璐 我一進(jìn)店門铲咨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人蜓洪,你說我怎么就攤上這事纤勒】煅梗” “怎么了诅愚?”我有些...
    開封第一講書人閱讀 158,300評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長胞四。 經(jīng)常有香客問我刚操,道長闸翅,這世上最難降的妖魔是什么再芋? 我笑而不...
    開封第一講書人閱讀 56,780評論 1 285
  • 正文 為了忘掉前任菊霜,我火速辦了婚禮,結(jié)果婚禮上济赎,老公的妹妹穿的比我還像新娘鉴逞。我一直安慰自己,他們只是感情好司训,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,890評論 6 385
  • 文/花漫 我一把揭開白布构捡。 她就那樣靜靜地躺著,像睡著了一般壳猜。 火紅的嫁衣襯著肌膚如雪勾徽。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,084評論 1 291
  • 那天统扳,我揣著相機(jī)與錄音喘帚,去河邊找鬼。 笑死咒钟,一個胖子當(dāng)著我的面吹牛吹由,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播朱嘴,決...
    沈念sama閱讀 39,151評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼倾鲫,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了萍嬉?” 一聲冷哼從身側(cè)響起乌昔,我...
    開封第一講書人閱讀 37,912評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎壤追,沒想到半個月后玫荣,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,355評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡大诸,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,666評論 2 327
  • 正文 我和宋清朗相戀三年捅厂,在試婚紗的時候發(fā)現(xiàn)自己被綠了贯卦。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,809評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡焙贷,死狀恐怖撵割,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情辙芍,我是刑警寧澤啡彬,帶...
    沈念sama閱讀 34,504評論 4 334
  • 正文 年R本政府宣布,位于F島的核電站故硅,受9級特大地震影響庶灿,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜吃衅,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,150評論 3 317
  • 文/蒙蒙 一往踢、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧徘层,春花似錦峻呕、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至跷敬,卻和暖如春讯私,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背西傀。 一陣腳步聲響...
    開封第一講書人閱讀 32,121評論 1 267
  • 我被黑心中介騙來泰國打工斤寇, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人池凄。 一個月前我還...
    沈念sama閱讀 46,628評論 2 362
  • 正文 我出身青樓抡驼,卻偏偏與公主長得像,于是被迫代替她去往敵國和親肿仑。 傳聞我的和親對象是個殘疾皇子致盟,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,724評論 2 351

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