標籤:
SQLite是Android內建的一個很小的關係型資料庫。SQLiteOpenHelper是一個用來輔助管理資料庫建立和版本升級問題的抽象類別。我們可以繼承這個抽象類別,實現它的一些方法來對資料庫進行自訂動作。下面兩個方法必須重寫:
- public void onCreate(SQLiteDatabase db)
- public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
另外SQLiteOpenHelper子類在構造執行個體時必須指定當前資料庫的名稱(name)、版本號碼(version)。而這裡名稱就決定了資料庫儲存時的檔案名稱,而這裡的版本號碼與App在AndroidMainfest.xml定義的versionCode沒有絕對關聯。也就是在App更新時如果資料庫的資料結構沒有發生變化那麼資料庫的版本號碼則不用增加。
onCreate:調用時機是使用者首次安裝應用後啟動,或是清除App資料庫檔案後啟動。這時可以在這個函數中完成初始的資料表的建立。
onUpgrade:調用時機是使用者在做應用程式更新,覆蓋安裝後啟動,如果新版本中資料庫版本號碼要比舊版本中的資料庫版本號碼高則會調用。這時可以在這個函數完成資料庫版本升級帶來的舊版本的相容問題,以及資料移轉問題。
還有一個一般情況下不需要重寫,但在應用出現逆向降級(如應用由版本號碼4降級安裝版本號碼為3的包)時必須重寫的方法onDowngrade,如果應用降級覆蓋安裝時沒有重寫該方法則會崩潰。
在資料庫版本升級時, 我們可能會遇到這樣一些情況:
- 需要擴充一個表的欄位
- 刪除掉原來表上某個冗餘的欄位
- 建立一個表
而處理上面這些問題都要在不損害舊資料庫曆史資料的前提下完成。這裡我們假設使用者手機上之前安裝的是資料庫版本為1的包,升級安裝的是資料庫版本號碼為2的包。這時我們要在資料庫版本為2的包在去處理這些升級邏輯。
首先是擴充一個表的欄位在onUpgrade中的實現為:
[java] view plain copy
- @Override
- public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
- //舊資料庫版本為1,才為表pedant添加一個student_name欄位
- if(oldVersion < 2) {
- db.execSQL("ALTER TABLE pedant ADD COLUMN student_name text");
- }
- }
SQLite對ALTER TABLE的支援是有限的,你可以在一個存在表上添加一個欄位到末尾,或者是改變表的名稱。但如果你想做更複雜的操作,比如刪除一個表已有的欄位,就要重新建立這個表並完成資料移轉,而不能使用DROP COLUMN這樣方便的命令了。詳見SQLite Frequently Questions
比如表pedant原來有三個欄位a、b、c,現在想刪除c欄位,那麼在onUpgrade中寫法如下:
[java] view plain copy
- @Override
- public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
- //舊資料庫版本為1,刪除表pedant的c欄位
- if(oldVersion < 2) {
- db.beginTransaction();
- try {
- db.execSQL("CREATE TEMPORARY TABLE pe_backup (a, b);");
- db.execSQL("INSERT INTO pe_backup SELECT a, b FROM pedant;");
- db.execSQL("DROP TABLE pedant;");
- db.execSQL("CREATE TABLE pedant(a text, b text);");
- db.execSQL("INSERT INTO pedant SELECT a, b FROM pe_backup;");
- db.execSQL("DROP TABLE pe_backup;");
- db.setTransactionSuccessful();
- } finally {
- db.endTransaction();
- }
- }
- }
這樣就既完成了對c欄位的刪除也保留了原來表上的資料。
最後一種情況最簡單直接執行CREATE語句就要可以了。
[java] view plain copy
- @Override
- public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
- //舊資料庫版本為1,建立新表newtb
- if(oldVersion < 2) {
- db.execSQL("CREATE TABLE newtb(a text, b text);");
- }
- }
資料庫在做升級時我們能明確地知道當前我們要對各舊錶進行什麼樣的操作來相容新版本。但如果在資料庫降級時,情況就不一樣了,針對我們開發新版本2時, 我們不能明確地知道以後的新版本比如版本3、4的資料庫結構走向是怎樣的。比如以後使用者從版本3回退到我們正在開發的版本2,由於我們開發當時不能預知版本3的表結構,不知版本3的資料表能否相容到版本2(假如版本3升級時刪除了一個版本2一直在用的表欄位,這時回退資料結構可能就不相容了),那麼我們在開發版本2時最穩妥的做法是重寫onDowngrade時把所有目前的版本將用到的表全部重建,即降級時扔掉以前全部的資料。
// 因為我們無法預知未來版本的表結構,向下相容時最穩妥的方法就是將該版本自己需要的表重構一次@Overridepublic void onDowngrade (SQLiteDatabase db, int oldVersion, int newVersion) { db.execSQL("DROP TABLE IF EXISTS t1;"); db.execSQL("DROP TABLE IF EXISTS t2;"); db.execSQL("DROP TABLE IF EXISTS t3;"); db.execSQL("DROP TABLE IF EXISTS t4;"); .... onCreate(db); // 建表}
Android版本更新時對SQLite資料庫升級或者降級遇到的問題