Android SQLite教程:內(nèi)部架構(gòu)及SQLite使用辦法
SQLite 介紹
SQLite一個非常流行的嵌入式數(shù)據(jù)庫,它支持SQL語言,并且只利用很少的內(nèi)存就有很好的性能。由于JDBC不適合手機這種內(nèi)存受限設備,所以Android開發(fā)人員需要學習新的API 來使用SQLite。此外它還是開源的,任何人都可以使用它。許多開源項目((Mozilla, PHP, Python)都使用了SQLite.
SQLite由以下幾個組件組成:SQL編譯器、內(nèi)核、后端以及附件。SQLite通過利用虛擬機和虛擬數(shù)據(jù)庫引擎(VDBE),使調(diào)試、修改和擴展SQLite的內(nèi)核變得更加方便。

SQLite 基本上符合 SQL-92 標準,和其他的主要 SQL 數(shù)據(jù)庫沒什么區(qū)別。它的優(yōu)點就是高效,Android 運行時環(huán)境包含了完整的 SQLite。
SQLite 和其他數(shù)據(jù)庫***的不同就是對數(shù)據(jù)類型的支持,創(chuàng)建一個表時,可以在 CREATE TABLE 語句中指定某列的數(shù)據(jù)類型,但是你可以把任何數(shù)據(jù)類型放入任何列中。當某個值插入數(shù)據(jù)庫時,SQLite 將檢查它的類型。如果該類型與關聯(lián)的列不匹配,則 SQLite 會嘗試將該值轉(zhuǎn)換成該列的類型。如果不能轉(zhuǎn)換,則該值將作為其本身具有的類型存儲。比如可以把一個字符串(String)放入 INTEGER 列。SQLite 稱這為“弱類型”(manifest typing.)。
此外,SQLite 不支持一些標準的 SQL 功能,特別是外鍵約束(FOREIGN KEY constrains),嵌套 transcaction 和 RIGHT OUTER JOIN 和 FULL OUTER JOIN, 還有一些 ALTER TABLE 功能。
除了上述功能外,SQLite 是一個完整的 SQL 系統(tǒng),擁有完整的觸發(fā)器,交易等等。
Android 集成了 SQLite 數(shù)據(jù)庫
Android 在運行時(run-time)集成了 SQLite,所以每個 Android 應用程序都可以使用 SQLite 數(shù)據(jù)庫。對于熟悉 SQL 的開發(fā)人員來時,在 Android 開發(fā)中使用 SQLite 相當簡單。但是,由于 JDBC 會消耗太多的系統(tǒng)資源,所以 JDBC 對于手機這種內(nèi)存受限設備來說并不合適。因此,Android 提供了一些新的 API 來使用 SQLite 數(shù)據(jù)庫,Android 開發(fā)中,程序員需要學使用這些 API。
數(shù)據(jù)庫存儲在 data/< 項目文件夾 >/databases/ 下。
Android開發(fā)中使用SQLite數(shù)據(jù)庫
Activites可以通過Content Provider或者Service訪問一個數(shù)據(jù)庫。下面會詳細講解如果創(chuàng)建數(shù)據(jù)庫,添加數(shù)據(jù)和查詢數(shù)據(jù)庫。
創(chuàng)建數(shù)據(jù)庫
Android不自動提供數(shù)據(jù)庫。在Android應用程序中使用SQLite,必須自己創(chuàng)建數(shù)據(jù)庫,然后創(chuàng)建表、索引,填充數(shù)據(jù)。Android 提供了 SQLiteOpenHelper 幫助你創(chuàng)建一個數(shù)據(jù)庫,你只要繼承 SQLiteOpenHelper 類,就可以輕松的創(chuàng)建數(shù)據(jù)庫。SQLiteOpenHelper 類根據(jù)開發(fā)應用程序的需要,封裝了創(chuàng)建和更新數(shù)據(jù)庫使用的邏輯。SQLiteOpenHelper 的子類,至少需要實現(xiàn)三個方法:
- 構(gòu)造函數(shù),調(diào)用父類 SQLiteOpenHelper 的構(gòu)造函數(shù)。這個方法需要四個參數(shù):上下文環(huán)境(例如,一個 Activity),數(shù)據(jù)庫名字,一個可選的游標工廠(通常是 Null),一個代表你正在使用的數(shù)據(jù)庫模型版本的整數(shù)。
- onCreate()方法,它需要一個 SQLiteDatabase 對象作為參數(shù),根據(jù)需要對這個對象填充表和初始化數(shù)據(jù)。
- onUpgrage() 方法,它需要三個參數(shù),一個 SQLiteDatabase 對象,一個舊的版本號和一個新的版本號,這樣你就可以清楚如何把一個數(shù)據(jù)庫從舊的模型轉(zhuǎn)變到新的模型。
下面示例代碼展示了如何繼承 SQLiteOpenHelper 創(chuàng)建數(shù)據(jù)庫:
- public class DatabaseHelper extends SQLiteOpenHelper {
- DatabaseHelper(Context context, String name, CursorFactory cursorFactory, int version)
- {
- super(context, name, cursorFactory, version);
- }
- @Override
- public void onCreate(SQLiteDatabase db) {
- // TODO 創(chuàng)建數(shù)據(jù)庫后,對數(shù)據(jù)庫的操作
- }
- @Override
- public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
- // TODO 更改數(shù)據(jù)庫版本的操作
- }
- @Override
- public void onOpen(SQLiteDatabase db) {
- super.onOpen(db);
- // TODO 每次成功打開數(shù)據(jù)庫后首先被執(zhí)行
- }
- }
接下來討論具體如何創(chuàng)建表、插入數(shù)據(jù)、刪除表等等。調(diào)用 getReadableDatabase() 或 getWriteableDatabase() 方法,你可以得到 SQLiteDatabase 實例,具體調(diào)用那個方法,取決于你是否需要改變數(shù)據(jù)庫的內(nèi)容:
- db=(new DatabaseHelper(getContext())).getWritableDatabase();
- return (db == null) ? false : true;
上面這段代碼會返回一個 SQLiteDatabase 類的實例,使用這個對象,你就可以查詢或者修改數(shù)據(jù)庫。
當你完成了對數(shù)據(jù)庫的操作(例如你的 Activity 已經(jīng)關閉),需要調(diào)用 SQLiteDatabase 的 Close() 方法來釋放掉數(shù)據(jù)庫連接。
創(chuàng)建表和索引
為了創(chuàng)建表和索引,需要調(diào)用 SQLiteDatabase 的 execSQL() 方法來執(zhí)行 DDL 語句。如果沒有異常,這個方法沒有返回值。
例如,你可以執(zhí)行如下代碼:
- db.execSQL("CREATE TABLE mytable (_id INTEGER PRIMARY KEY
- AUTOINCREMENT, title TEXT, value REAL);");
這條語句會創(chuàng)建一個名為 mytable 的表,表有一個列名為 _id,并且是主鍵,這列的值是會自動增長的整數(shù)(例如,當你插入一行時,SQLite 會給這列自動賦值),另外還有兩列:title( 字符 ) 和 value( 浮點數(shù) )。 SQLite 會自動為主鍵列創(chuàng)建索引。
通常情況下,***次創(chuàng)建數(shù)據(jù)庫時創(chuàng)建了表和索引。如果你不需要改變表的 schema,不需要刪除表和索引 . 刪除表和索引,需要使用 execSQL() 方法調(diào)用 DROP INDEX 和 DROP TABLE 語句。
給表添加數(shù)據(jù)
上面的代碼,已經(jīng)創(chuàng)建了數(shù)據(jù)庫和表,現(xiàn)在需要給表添加數(shù)據(jù)。有兩種方法可以給表添加數(shù)據(jù)。
像上面創(chuàng)建表一樣,你可以使用 execSQL() 方法執(zhí)行 INSERT, UPDATE, DELETE 等語句來更新表的數(shù)據(jù)。execSQL() 方法適用于所有不返回結(jié)果的 SQL 語句。例如:
- db.execSQL("INSERT INTO widgets (name, inventory)"+
- VALUES ('Sprocket', 5)");
另一種方法是使用 SQLiteDatabase 對象的 insert(), update(), delete() 方法。這些方法把 SQL 語句的一部分作為參數(shù)。示例如下:
- ContentValues cv=new ContentValues();
- cv.put(Constants.TITLE, "example title");
- cv.put(Constants.VALUE, SensorManager.GRAVITY_DEATH_STAR_I);
- db.insert("mytable", getNullColumnHack(), cv);
update()方法有四個參數(shù),分別是表名,表示列名和值的 ContentValues 對象,可選的 WHERE 條件和可選的填充 WHERE 語句的字符串,這些字符串會替換 WHERE 條件中的“?”標記。update() 根據(jù)條件,更新指定列的值,所以用 execSQL() 方法可以達到同樣的目的。
WHERE 條件和其參數(shù)和用過的其他 SQL APIs 類似。例如:
- String[] parms=new String[] {"this is a string"};
- db.update("widgets", replacements, "name=?", parms);
delete() 方法的使用和 update() 類似,使用表名,可選的 WHERE 條件和相應的填充 WHERE 條件的字符串。
查詢數(shù)據(jù)庫
類似 INSERT, UPDATE, DELETE,有兩種方法使用 SELECT 從 SQLite 數(shù)據(jù)庫檢索數(shù)據(jù)。
1 .使用 rawQuery() 直接調(diào)用 SELECT 語句;
使用 query() 方法構(gòu)建一個查詢。
Raw Queries
正如 API 名字,rawQuery() 是最簡單的解決方法。通過這個方法你就可以調(diào)用 SQL SELECT 語句。例如:
- Cursor c=db.rawQuery(
- "SELECT name FROM sqlite_master WHERE type='table' AND name='mytable'", null);
在上面例子中,我們查詢 SQLite 系統(tǒng)表(sqlite_master)檢查 table 表是否存在。返回值是一個 cursor 對象,這個對象的方法可以迭代查詢結(jié)果。
如果查詢是動態(tài)的,使用這個方法就會非常復雜。例如,當你需要查詢的列在程序編譯的時候不能確定,這時候使用 query() 方法會方便很多。
Regular Queries
query() 方法用 SELECT 語句段構(gòu)建查詢。SELECT 語句內(nèi)容作為 query() 方法的參數(shù),比如:要查詢的表名,要獲取的字段名,WHERE 條件,包含可選的位置參數(shù),去替代 WHERE 條件中位置參數(shù)的值,GROUP BY 條件,HAVING 條件。
除了表名,其他參數(shù)可以是 null。所以,以前的代碼段可以可寫成:
- String[] columns={"ID", "inventory"};
- String[] parms={"snicklefritz"};
- Cursor result=db.query("widgets", columns, "name=?",parms, null, null, null);
使用游標
不管你如何執(zhí)行查詢,都會返回一個 Cursor,這是 Android 的 SQLite 數(shù)據(jù)庫游標,使用游標,你可以:
- 通過使用 getCount() 方法得到結(jié)果集中有多少記錄;
- 通過 moveToFirst(), moveToNext(), 和 isAfterLast() 方法遍歷所有記錄;
- 通過 getColumnNames() 得到字段名;
- 通過 getColumnIndex() 轉(zhuǎn)換成字段號;
- 通過 getString(),getInt() 等方法得到給定字段當前記錄的值;
- 通過 requery() 方法重新執(zhí)行查詢得到游標;
- 通過 close() 方法釋放游標資源;
例如,下面代碼遍歷 mytable 表
- Cursor result=db.rawQuery("SELECT ID, name, inventory FROM mytable");
- result.moveToFirst();
- while (!result.isAfterLast()) {
- int id=result.getInt(0);
- String name=result.getString(1);
- int inventory=result.getInt(2);
- // do something useful with these
- result.moveToNext();
- }
- result.close();
在 Android 中使用 SQLite 數(shù)據(jù)庫管理工具
在其他數(shù)據(jù)庫上作開發(fā),一般都使用工具來檢查和處理數(shù)據(jù)庫的內(nèi)容,而不是僅僅使用數(shù)據(jù)庫的 API。使用 Android 模擬器,有兩種可供選擇的方法來管理數(shù)據(jù)庫。
首先,模擬器綁定了 sqlite3 控制臺程序,可以使用 adb shell 命令來調(diào)用他。只要你進入了模擬器的 shell,在數(shù)據(jù)庫的路徑執(zhí)行 sqlite3 命令就可以了。數(shù)據(jù)庫文件一般存放在:
/data/data/your.app.package/databases/your-db-name |
如果你喜歡使用更友好的工具,你可以把數(shù)據(jù)庫拷貝到你的開發(fā)機上,使用 SQLite-aware 客戶端來操作它。這樣的話,你在一個數(shù)據(jù)庫的拷貝上操作,如果你想要你的修改能反映到設備上,你需要把數(shù)據(jù)庫備份回去。
把數(shù)據(jù)庫從設備上考出來,你可以使用 adb pull 命令(或者在 IDE 上做相應操作)。存儲一個修改過的數(shù)據(jù)庫到設備上,使用 adb push 命令。
一個最方便的 SQLite 客戶端是 FireFox SQLite Manager 擴展,它可以跨所有平臺使用。

結(jié)束語
如果你想要開發(fā) Android 應用程序,一定需要在 Android 上存儲數(shù)據(jù),使用 SQLite 數(shù)據(jù)庫是一種非常好的選擇。本文介紹了如何在 Android 應用程序中使用 SQLite 數(shù)據(jù)庫 ,主要介紹了在 Android 應用程序中使用 SQLite 創(chuàng)建數(shù)據(jù)庫和表、添加數(shù)據(jù)、更新和檢索數(shù)據(jù),還介紹了比較常用的 SQLite 管理工具,通過閱讀本文,你可以在 Android 中輕松操作 SQLite 數(shù)據(jù)庫。