1. 程式人生 > >一篇好文之Android資料庫 SQLite全解析

一篇好文之Android資料庫 SQLite全解析

在這裡插入圖片描述
這篇文章是資料庫系列篇文章的第一篇,主要講Android Sqlite資料庫儲存,後面陸續出GreenDao,LitePal, Realm,wcdb的文章,一如既往,如果遇到任何關於Android中SQLite的問題,都可以直接在我的文章底部留言,或者直接在我的公眾號aserbao留言,文章會持續更新,希望這篇文章能為大家提供到幫助!如果覺得文章對你有用,就幫忙點個贊,若覺得文章寫得不好之處望指出,必將加以修正!
在這裡插入圖片描述

這篇文章主要講SQlite資料庫儲存,從資料庫建表到資料庫的增刪改查操作,再到資料庫升級操作,最後是文章總結及參考連結

專案效果地址:

SQlite

1. 建立資料庫

Android中使用SQlite,需要自己建立庫,建表,新增資料!好在Android中提供了SQLiteOpenHelper類來幫助建立使用資料庫,我們只需要繼承這個類就可以實現資料庫的建立和對資料的操作了!Android 中建立資料庫需要通過如下幾部:

  1. 建立一個類繼承SQLiteOpenHelper,需要實現其三個方法:
    • 構造方法:需要給SQLiteOpenHelper傳遞四個引數:(上下文,資料庫名,遊標工廠(通常為null),當前資料庫版本號);
    • onCreate(): 表的建立,初始化操作
    • onUpgrade(): 表升級
    • 還有:onDowngrade(): 表降級,onOpen:每次開啟資料庫,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的資料型別 :

作用
NULL: 這個值為空值
VARCHAR(n): 長度不固定且其最大長度為 n 的字串,n不能超過 4000。
CHAR(n): 長度固定為n的字串,n不能超過 254。
INTEGER: 值被標識為整數,依據值的大小可以依次被儲存為1,2,3,4,5,6,7,8.
REAL: 所有值都是浮動的數值,被儲存為8位元組的IEEE浮動標記序號.
TEXT: 值為文字字串,使用資料庫編碼儲存(TUTF-8, UTF-16BE or UTF-16-LE).
BLOB: 值是BLOB資料塊,以輸入的資料格式進行儲存。如何輸入就如何儲存,不改 變格式。
DATA: 包含了 年份、月份、日期。
TIME: 包含了 小時、分鐘、秒。

2. 建立一個數據庫儲存物件

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. 建立一個數據庫控制器實現增刪改查

1. 增

  1. 使用Android APi來實現增加資料
 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語句實現增加資料
 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. 資料庫的升級

在開發的過程中,我們避免不了需要修改資料庫結構,新增欄位或者刪除欄位!我們通過增加傳遞給SQLiteOpenHelper的版本值,得到onUpgrade方法的回撥來實現對資料庫的操作來進行升級。這裡需要注意的是,如果使用者安裝版本1之後直接跳裝版本3,這時候我們就需要在onUpgrade方法中通過oldVersion來進行每一個版本的逐漸升級,方法如下:


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", "版本升級後的資料");
        db.update(ThingDBController.TABLE_NAME, values, null, null);
    }
}

問題

查詢問題

Cursor只會擁有你查詢的資料,如果在查詢條件裡面沒有申請,Cursor裡面就不會包含這個值,就會出現如下異常:
錯誤寫法:

 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)));//這裡進行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)

參考連結

相關推薦

Android資料庫 SQLite解析

這篇文章是資料庫系列篇文章的第一篇,主要講Android Sqlite資料庫儲存,後面陸續出GreenDao,LitePal, Realm,wcdb的文章,一如既往,如果遇到任何關於Android中SQLite的問題,都可以直接在我的文章底部留言,或者直接在我

Android資料庫GreenDao的完全解析

今日科技快訊 小米近日稱,財政部此次公告的檢查為2017年財政部會計監督檢查,是針對2016年的會計資訊質量進行的檢查。公司存在部分費用攤銷核算錯誤、對外贈送商品未作為視同銷售行為申報繳稅、報銷發票管理不規範、費用管理制度不完善等問題。以上問題均已整改完成,並獲得財政部

Android 呼叫C程式碼及生成除錯so庫

不靠譜的朱先生又來了,今天是週五,我又出現了!好了,不為自己多解釋,上週沒發文章,其實我寫了,只是沒有發出來而已……機智ovo。 上週寫的文章是關於GreenDao全面解析,其實當時是想寫一個關於資料庫的系列文章,後來一共就寫了兩篇,SQlite全面解析和GreenDao全面解析。至

Android文字軟鍵盤

已經有一個多月沒有寫文章了,當然,我沒失蹤,我還活著!因為換了新的工作環境,所以在接手專案的時候花了點時間……不為自己做過多借口,今後持續更新好內容(還是希望自己能周更)! 這篇文章最初是記錄一個全屏模式下輸入框被軟鍵盤覆蓋的問題,要求背景不動,輸入框上移!碰

異步原創征集令,本書!

Markdown 活動征集 點擊上方“異步社區”,選擇“置頂公眾號”技術幹貨,第一時間送達各位異步社區的小夥伴和大神,大家好!我是你們的異步君,就是一直被你們吐槽的,躲在異步客服後面的異步君。對,尤其最近新版上線後,被吐槽更激烈的異步君!之前大家一致吐槽異步君:想在異步社區寫個技術文章都難啊!社區編輯

推薦《佛教真像大家所認為的那樣消極嗎?》

推薦一篇好文《佛教真像大家所認為的那樣消極嗎?》   差不多一年前關注了一個叫“學佛導航”的公眾號,它都是發表一些“雞湯文”與“養生文”,譬如什麼什麼菩薩過生日啦,做了什麼好事又有福報啦云云。雖然鄙人從小對佛教文化耳融目染,家中不僅大部分人對於佛教十分虔誠而且還有親戚是很專業

轉發:36氪翻譯自medium的文章: 讀書沒有 KPI:為什麼堅持“年讀 100 本書”沒用?

你只是為了達成所謂的數量目標而讀書。 編者按:讀書本是一項安靜、緩慢的活動,但隨著現代社會節奏的加快,資訊科技的廣泛普及,讀書這一行為模式也開始發生了變化。越來越多的人開始碎片化閱讀,並且越來越多的文章推崇速讀或者是一年讀多少本書才能實現自我提升等觀點。Jotform 創始人 Aytekin Tank

的軟就應該有一個的標題

老板 好的 字型 若是 hone 也不會 必須 疑問 公司 無論是什麽樣的軟文,讀者群體接觸的第一眼就是標題,一個好的標題,那麽這篇文章基本就成功了一半,如若是標題並不能吸引人的眼球,那麽即使文章寫得再好,會點進去的讀者也不會多。 以下是維貝工作室根據多年軟文推廣營銷的經驗

移動APP測試基礎效能測試流程-

https://www.oschina.net/question/2562975_2218004 評估App的時間和空間特性 : 極限測試:在各種邊界壓力情況下,如電池、儲存、網速等,驗證App是否能正確響應。 --記憶體滿時安裝App --執行App時手機斷

多執行緒程式設計Linux環境下的多執行緒()——

一、Linux環境下的執行緒   相對於其他作業系統,Linux系統核心只提供了輕量級程序的支援,並未實現執行緒模型。Linux是一種“多程序單執行緒”的作業系統,Linux本身只有程序的概念,而其所謂的“執行緒”本質上在核心裡仍然是程序。      程序是資源分配的單位,同一程序中的多個執行緒共享該程序的

將課程作業01的設計思想、程序流程圖、源程序代碼和結果截圖整理成

package static 技術分享 整理 public out 計算 mage 數字 1.程序設計思想 先讓用戶輸入要計算的數字的個數,然後讓用戶輸入這幾個數,將字符型轉化為整數,然後求和,最後輸出所求得的和即可。 2.程序流程圖 3.源程序代碼 pack

將課程作業01、02、03的設計思想、源程序代碼和結果截圖整理成。。

top exception 漢諾塔 一個數 resource valueof val 作業 回文數 信1605-3 於丁一 20163578 使用組合數公式利用n!來計算 設計思想:首先要判斷一個數的階乘如何表達,然後調用方法用組合數公式,最後求出組合數。 packag

2018年3月19日推薦文章精選 “打盡”

文章精選 精選 好文 區塊鏈,工作證明(POW)代碼+原理 golang版剖析 作者:64180190簡介:在本文中,我們將討論哈希值。哈希是獲取指定數據的哈希值的過程。 哈希值是對其計算的數據的唯一表示。 哈希函數是一個獲取任意大小的數據並產生固定大小的哈希的函數。 以下是哈希的一些主要功能:

通過PHP把英文件中所有單詞的首字母轉為大寫

index.php程式碼如下:     <?php     header("Content-type: text/html; charset=utf8");      &n

android 資料庫 SQLite

public class SqliteHelper extends SQLiteOpenHelper{ private static String db_name="mydb.db"; private static int db_version=1; public Sql

Android資料庫sqlite儲存

一、修改佈局檔案 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layo

網上看中文章,無法複製?不要著急,一個程式碼,教你搞定!

不知道大家有沒有和我一樣的苦惱,在網上看到自己很感興趣,很喜歡的文章,卻不能複製!真的很討厭! 後來我學會了一個小技巧——一個程式碼,即可複製你看中的任何內容! 你想學習嗎?想的話,就接著往下看喲! 應用舉例: 如圖,這篇文章想要下載,就需要註冊登入才可以。 其

CSDN如何轉載的文章

轉載CSDN部落格步驟: 1.CSDN部落格頁面右鍵,點選【檢查】 點選檢查後,頁面右側出現html程式碼,如下圖 2.如果需要轉載全文,則在html程式碼下側點選選中article_content 即可,會在程式碼框中自動選中article_

關於sprintf,好不容易從網上找到了文章也給大家發一下吧

這個程式碼算原創有些勉強,不管怎樣粘過去,可以用在win下除錯的,我看過這個後,儘管仍然有很多迷惑,不過覺得比以前更直觀了,有了那麼一點點感覺。 #include <stdio.h> typedef char *va_list; // 此處程式碼看了兩種

關於套接字(sockets)入門的文章

套接字程式設計(sockets 譯文) 作者:Kameswari Chebrolu (印度理工學院坎普爾分校電子工程系) 卡門斯瓦力 車布羅 背景 多路解編 ●轉變“主機到主機的資料包傳輸服務”到“程式到程式的資料交流通道” 位元組次序 ●兩類“位