2.1 SQLite數據庫的創建和升級

點此進入:從零快速構建APP系列目錄導圖
點此進入:UI編程系列目錄導圖
點此進入:四大組件系列目錄導圖
點此進入:數據網絡和線程系列目錄導圖
本節例程下載地址:WillFlowDatabast

一、SQLite簡介

**SQLite 是一款輕量級的關係型數據庫,它的運算速度非常快,佔用資源很少,通常只需要幾百 K 的內存就足夠了,因而特別適合在移動設備上使用。**SQLite 不僅支持標準的 SQL 語法,還遵循了數據庫的 ACID 事務,所以只要你以前使用過其他的關係型數據庫,就可以很快地上手 SQLite。而 SQLite 又比一般的數據庫要簡單得多,它甚至不用設置用戶名和密碼就可以使用。 Android 正是把這個功能極爲強大的數據庫嵌入到了系統當中,使得本地持久化的功能有了一次質的飛躍。

前面我們所學的文件存儲和 SharedPreferences 存儲畢竟只適用於去保存一些簡單的數據和鍵值對,當需要存儲大量複雜的關係型數據的時候,你就會發現以上兩種存儲方式很難應付得了。比如我們手機的短信程序中可能會有很多個會話,每個會話中又包含了很多條信息內容,並且大部分會話還可能各自對應了電話簿中的某個聯繫人。很難想象如何用文件或者 SharedPreferences 來存儲這些數據量大、結構性複雜的數據吧?但是使用數據庫就可以做得到。那麼我們就趕快來看一看, Android 中的 SQLite 數據庫到底是如何使用的。

二、創建數據庫

Android 爲了讓我們能夠更加方便地管理數據庫,專門提供了一個 SQLiteOpenHelper 幫助類,藉助這個類就可以非常簡單地對數據庫進行創建和升級。

首先我們要知道 SQLiteOpenHelper 是一個抽象類,這意味着如果我們想要使用它的話,就需要創建一個自己的幫助類去繼承它。 SQLiteOpenHelper 中有兩個抽象方法,分別是 onCreate() 和 onUpgrade(),我們必須在自己的幫助類裏面重寫這兩個方法,然後分別在這兩個方法中去實現創建、升級數據庫的邏輯。

SQLiteOpenHelper 中還有兩個非常重要的實例方法,getReadableDatabase() 和 getWritableDatabase()。這兩個方法都可以創建或打開一個現有的數據庫(如果數據庫已存在則直接打開,否則創建一個新的數據庫),並返回一個可對數據庫進行讀寫操作的對象。不同的是,當數據庫不可寫入的時候(如磁盤空間已滿) getReadableDatabase()方法返回的對象將以只讀的方式去打開數據庫,而 getWritableDatabase()方法則將出現異常。

SQLiteOpenHelper 中有兩個構造方法可供重寫,一般使用參數少一點的那個構造方法即可。這個構造方法中接收四個參數:
第一個參數是 Context,這個沒什麼好說的,必須要有它才能對數據庫進行操作。
第二個參數是數據庫名,創建數據庫時使用的就是這裏指定的名稱。
第三個參數允許我們在查詢數據的時候返回一個自定義的 Cursor,一般都是傳入 null。
第四個參數表示當前數據庫的版本號,可用於對數據庫進行升級操作。

構建出 SQLiteOpenHelper 的實例之後,再調用它的 getReadableDatabase() 或 getWritableDatabase()方法就能夠創建數據庫了,數據庫文件會存放在/data/data//databases/目錄下。此時,重寫的 onCreate() 方法也會得到執行,所以通常會在這裏去處理一些創建表的邏輯。接下來還是讓我們通過例子的方式來更加直觀地體會 SQLiteOpenHelper 的用法吧。

這裏我們希望創建一個名爲 BookStore.db 的數據庫,然後在這個數據庫中新建一張 Book 表,表中有 id( 主鍵)、作者、價格、 頁數和書名等列。創建數據庫表當然還是需要用建表語句的,這裏也是要考驗一下我們的 SQL 基本功了,Book 表的建表語句如下所示:

    create table Book (
            id integer primary key autoincrement,
            author text,
            price real,
            pages integer,
            name text)

只要你對 SQL 方面的知識稍微有一些瞭解,上面的建表語句對你來說應該都不難。SQLite 不像其他的數據庫擁有衆多繁雜的數據類型,它的數據類型很簡單:integer 表示整型,real 表示浮點型, text 表示文本類型, blob 表示二進制類型。 另外,上述建表語句中我們還使用了 primary key 將 id 列設爲主鍵,並用 autoincrement 關鍵字表示 id 列是自增長的。然後需要在代碼中去執行這條 SQL語句,才能完成創建表的操作。

新建 MyDatabaseHelper,代碼如下:
/**
 * Created by   : WGH.
 */
public class MyDatabaseHelper extends SQLiteOpenHelper {
    private Context mContext;

    public static final String CREATE_BOOK = "create table book ("
            + "id integer primary key autoincrement, "
            + "author text, "
            + "price real, "
            + "pages integer, "
            + "name text)";

    public MyDatabaseHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
        super(context, name, factory, version);
        this.mContext = context;
    }

    @Override
    public void onCreate(SQLiteDatabase sqLiteDatabase) {
        sqLiteDatabase.execSQL(CREATE_BOOK);
        Toast.makeText(mContext, "創建數據庫成功", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {

    }
}

我們把建表語句定義成了一個字符串常量,然後在 onCreate() 方法中又調用了 SQLiteDatabase 的 execSQL() 方法去執行這條建表語句,並彈出一個 Toast 提示創建成功,這樣就可以保證在數據庫創建完成的同時還能成功創建 Book 表。

修改 activity_main.xml 中的代碼,如下所示:
    <Button
        android:id="@+id/buttonDataBase"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="創建數據庫"
        android:textColor="#0babf5"
        android:textSize="25dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
最後修改 MainActivity 中的代碼,如下所示:
public class MainActivity extends AppCompatActivity {
    private MyDatabaseHelper myDatabaseHelper;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Button button = (Button) findViewById(R.id.buttonDataBase);
        myDatabaseHelper = new MyDatabaseHelper(this, "BookStore.db", null, 1);

        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                myDatabaseHelper.getWritableDatabase();
            }
        });
    }
}

這裏我們在 onCreate() 方法中構建了一個 MyDatabaseHelper 對象,並且通過構造函數的參數將數據庫名指定爲 BookStore.db,版本號指定爲 1,然後在 Create database 按鈕的點擊事件裏調用了 getWritableDatabase() 方法。這樣當第一次點擊 Create database 按鈕時,就會檢測到當前程序中並沒有 BookStore.db 這個數據庫,於是會創建該數據庫並調用 MyDatabaseHelper 中的 onCreate() 方法,這樣 Book 表也就得到了創建,然後會彈出一個 Toast 提示創建成功。再次點擊 Create database 按鈕時,會發現此時已經存在 BookStore.db 數據庫了,因此不會再創建一次。

編譯運行看效果:

此時 BookStore.db 數據庫和 Book 表應該都已經創建成功了,因爲當我們再次點擊按鈕時不會再有 Toast 彈出。可是又回到了之前的那個老問題,怎樣才能證實它們的確是創建成功了?如果還是使用 File Explorer,那麼最多你只能看到 databases 目錄下出現了一個 BookStore.db 文件, Book 表是無法通過 File Explorer 看到的。因此這次我們準備換一種查看方式,使用 adb shell 來對數據庫和表的創建情況進行檢查。

adb 是 Android SDK 中自帶的一個調試工具, 使用這個工具可以直接對連接在電腦上的手機或模擬器進行調試操作。更詳細的介紹你可以參看這裏:。。。

打開命令行界面,輸入 adb shell,就會進入到設備的控制檯,然後使用 cd 命令切換到 /data/data/com.example.databasetest/databases/ 目錄下, 並使用 ls 命令查看到該目錄裏的文件:

這個目錄下出現了兩個數據庫文件,一個正是我們創建的 BookStore.db,而另一個 BookStore.db-journal 則是爲了讓數據庫能夠支持事務而產生的臨時日誌文件,通常情況下這個文件的大小都是 0 字節。

接下來我們就要藉助 sqlite 命令來打開數據庫了,只需要鍵入 sqlite3,後面加上數據庫名即可:

然後就已經打開了 BookStore.db 數據庫,現在就可以對這個數據庫中的表進行管理了。首先來看一下目前數據庫中有哪些表,鍵入.table 命令:

可以看到此時數據庫中有兩張表,android_metadata 表是每個數據庫中都會自動生成的,而另外一張 Book 表就是我們在 MyDatabaseHelper 中創建的了。這裏還可以通過 .schema 命令來查看它們的建表語句:

由此證明, BookStore.db 數據庫和 Book 表確實已經是創建成功了。之後鍵入 .exit 或 .quit 命令可以退出數據庫的編輯,再鍵入 exit 命令就可以退出設備控制檯了。

三、升級數據庫

如果你足夠細心,一定會發現 MyDatabaseHelper 中還有一個 onUpgrade() 方法,它是用於對數據庫進行升級的,它在整個數據庫的管理工作當中起着非常重要的作用。目前我們已經有一張 Book 表用於存放書的各種詳細數據,如果我們想再添加一張 Category 表用於記錄書籍的分類比如: Category 表中有 id(主鍵)、分類名和分類代碼這幾個列,那麼建表語句就可以寫成:

    create table Category (
            id integer primary key autoincrement,
            category_name text,
            category_code integer)
將這條建表語句添加到 MyDatabaseHelper 中,代碼如下:
    private static final String CREATE_BOOK = "create table book ("
            + "id integer primary key autoincrement, "
            + "author text, "
            + "price real, "
            + "pages integer, "
            + "name text)";

    private static final String CREATE_CATEGORY = "create table Category ("
            + "id integer primary key autoincrement, "
            + "category_name text, "
            + "category_code integer)";

    public MyDatabaseHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
        super(context, name, factory, version);
        this.mContext = context;
    }

    @Override
    public void onCreate(SQLiteDatabase sqLiteDatabase) {
        sqLiteDatabase.execSQL(CREATE_BOOK);
        sqLiteDatabase.execSQL(CREATE_CATEGORY);
        Toast.makeText(mContext, "創建數據庫成功", Toast.LENGTH_SHORT).show();
    }

其實這個時候我們去點擊創建數據庫按鈕是不能成功的,因爲此時 BookStore.db 數據庫已經存在了,之後不管我們怎樣點擊創建數據庫按鈕, MyDatabaseHelper 中的 onCreate() 方法都不會再次執行,因此新添加的表也就無法得到創建了。所以我們需要運用 SQLiteOpenHelper 的升級功能解決這個問題。

修改 MyDatabaseHelper 中的代碼,如下所示:
    @Override
    public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
        sqLiteDatabase.execSQL("drop table if exists Book");
        sqLiteDatabase.execSQL("drop table if exists Category");
        onCreate(sqLiteDatabase);
    }

可以看到,我們在 onUpgrade() 方法中執行了兩條 DROP 語句,如果發現數據庫中已經存在 Book 表或 Category 表了,就將這兩張表刪除掉,然後再調用 onCreate() 方法去重新創建。這裏先將已經存在的表刪除掉,是因爲如果在創建表時發現這張表已經存在了,就會直接報錯。

接下來我們讓 onUpgrade( )方法能夠執行:看一下 SQLiteOpenHelper 的構造方法裏接收的第四個參數,它表示當前數據庫的版本號,之前我們傳入的是 1,現在只要傳入一個比 1 大的數,就可以讓 onUpgrade() 方法得到執行了。

修改 MainActivity 中的代碼,如下所示:
public class MainActivity extends AppCompatActivity {
    private MyDatabaseHelper myDatabaseHelper;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        ...
        myDatabaseHelper = new MyDatabaseHelper(this, "BookStore.db", null, 2);
        ...
    }
}

這裏將數據庫版本號指定爲 2,表示我們對數據庫進行升級了。現在重新運行程序,並點擊按鈕,這時就會再次彈出和剛纔一樣的創建成功提示。爲了驗證一下 Category 表是不是已經創建成功了,我們在 adb shell 中打開 BookStore.db 數據庫,然後鍵入.table 命令,結果如圖所示:

由此可以看出, Category 表已經創建成功了,同時也說明我們的升級功能的確起到了作用。

點此進入:GitHub開源項目“愛閱”,下面是“愛閱”的效果圖:


聯繫方式:

簡書:WillFlow
CSDN:WillFlow
微信公衆號:WillFlow

微信公衆號:WillFlow

發佈了81 篇原創文章 · 獲贊 21 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章