如果你對資料庫還完全陌生,請參考之前的三篇文章(第一篇、第二篇、第三篇)
因為很多人都不了解Android的資料庫更新應該怎麼做,所以在此寫一篇說明文好了
希望不了解的人看完之後能比較有所了解,下面開始解釋:
先貼上資料庫的程式碼,裡面當然也包含一般更新資料庫(onUpgrade)
程式碼
import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import android.database.sqlite.SQLiteDatabase.CursorFactory; public class NewListDataSQL extends SQLiteOpenHelper { private static final int VERSION = 3;//資料庫版本 public NewListDataSQL(Context context, String name, CursorFactory factory,int version) { //建構子 super(context, name, factory, version); } public NewListDataSQL(Context context,String name) { this(context, name, null, VERSION); } public NewListDataSQL(Context context, String name, int version) { this(context, name, null, version); } //輔助類建立時運行該方法 @Override public void onCreate(SQLiteDatabase db) { String DATABASE_CREATE_TABLE = "create table newMemorandum(" + "_ID INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL," + "date VARCHAR," + "note VARCHAR," + "pw VARCHAR," + "reminder INT," + "type VARCHAR," + "memo VARCHAR" + ")"; db.execSQL(DATABASE_CREATE_TABLE); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { //oldVersion=舊的資料庫版本;newVersion=新的資料庫版本 //db.execSQL("DROP TABLE IF EXISTS newMemorandum"); //刪除舊有的資料表 //onCreate(db); if (newVersion > oldVersion) { db.beginTransaction(); boolean success = true; switch (oldVersion) { case 2: Cursor cursor = db.rawQuery("select _ID,date from newMemorandum", null); int[] iID = new int[cursor.getCount()]; String[] sDate = new String[cursor.getCount()]; int rows_num = cursor.getCount(); //取得資料表列數 if(rows_num != 0) { cursor.moveToFirst(); //將指標移至第一筆資料 for(int i=0; i<rows_num; i++) { int iCr = cursor.getInt(0); String strCr = cursor.getString(1); iID[i]=iCr; sDate[i]=strCr.split(" ")[0].split("/")[0] + "/" + String.valueOf(Integer.valueOf(strCr.split(" ")[0].split("/")[1])) + "/" + String.valueOf(Integer.valueOf(strCr.split(" ")[0].split("/")[2])) + " " + strCr.split(" ")[2]; //因為日期格式有變,所以重新更新 //格式改為2012/6/6 12:02 ContentValues cv = new ContentValues(); cv.put("date", sDate[i]); db.update("newMemorandum", cv, "_ID=" + iID[i], null); cv = null;//消滅物件 cursor.moveToNext(); //將指標移至下一筆資料 } } cursor.close(); //關閉Cursor db.execSQL("ALTER TABLE newMemorandum ADD COLUMN reminder integer DEFAULT 0"); db.execSQL("ALTER TABLE newMemorandum ADD COLUMN type VARCHAR"); db.execSQL("ALTER TABLE newMemorandum ADD COLUMN memo VARCHAR"); oldVersion++; success = true; break; case 1: Cursor cursor2 = db.rawQuery("select _ID,date from newMemorandum", null); int[] iID2 = new int[cursor2.getCount()]; String[] sDate2 = new String[cursor2.getCount()]; int rows_num2 = cursor2.getCount(); //取得資料表列數 if(rows_num2 != 0) { cursor2.moveToFirst(); //將指標移至第一筆資料 for(int j=0; j<rows_num2; j++) { int iCr2 = cursor2.getInt(0); String strCr = cursor2.getString(1); iID2[j]=iCr2; sDate2[j]=strCr.split(" ")[0].split("/")[0] + "/" + String.valueOf(Integer.valueOf(strCr.split(" ")[0].split("/")[1])) + "/" + String.valueOf(Integer.valueOf(strCr.split(" ")[0].split("/")[2])) + " " + strCr.split(" ")[2]; //因為日期格式有變,所以重新更新 //格式改為2012/6/6 12:02 ContentValues cv2 = new ContentValues(); cv2.put("date", sDate2[j]); db.update("newMemorandum", cv2, "_ID=" + iID2[j], null); cv2 = null;//消滅物件 cursor2.moveToNext(); //將指標移至下一筆資料 } } cursor2.close(); //關閉Cursor db.execSQL("ALTER TABLE newMemorandum ADD COLUMN pw VARCHAR"); db.execSQL("ALTER TABLE newMemorandum ADD COLUMN reminder integer DEFAULT 0"); db.execSQL("ALTER TABLE newMemorandum ADD COLUMN type VARCHAR"); db.execSQL("ALTER TABLE newMemorandum ADD COLUMN memo VARCHAR"); oldVersion = 3; success = true; break; } if (success) { db.setTransactionSuccessful(); } db.endTransaction(); } else { onCreate(db); } } @Override public void onOpen(SQLiteDatabase db) { super.onOpen(db); // TODO 每次成功打開數據庫後首先被執行 } @Override public synchronized void close() { super.close(); // TODO 每次關閉數據庫後被執行 } }
說明:
此為資料庫SQLiteOpenHelper類的程式碼,幾個地方分析
1.資料庫的執行方式
當系統要new出SQLiteOpenHelper類時,會先去找應用程式的DB資料夾下是否有該資料庫
如果沒有就執行建構子及onCreate建構該類別
如果有就執行onUpgrade更新資料庫
2.private static final int VERSION = 3;//資料庫版本 代表的意義與作用
(1)如果手機中沒有該應用程式,也等於沒有該資料庫(因為資料庫是獨立個體)
就會執行建構子構建該資料庫,建構子會帶入此VERSION,也就是從第3版開始
之後的更新也是從第4版開始,不能再回到第1版開始。
(2)如果有資料庫就會跳到onUpgrade事件中
oldVersion=舊的資料庫版本
newVersion=新的資料庫版本
這兩個是怎麼出現的呢?
在要更新資料庫時,您之前的VERSION一定是寫成這樣VERSION = 2
VERSION = 2 就是 = oldVersion
程式有修改時,資料庫也有修改,這時也會把VERSION改為VERSION = 3
VERSION = 3 就是 = newVersion
當你更新資料庫時,程式判別出VERSION = 3比之前的VERSION = 2大時
就會自動跳到onUpgrade事件中,帶入oldVersion=2、newVersion=3
當然你的舊版也可能是VERSION = 1(因為沒有即時更新)
程式還是會帶入oldVersion=1、newVersion=3
3.onUpgrade資料庫更新
(1)當我們了解了程式是怎麼判別資料庫更新後,再來看資料庫是怎麼更新的
因為舊版本可能不一樣,有可能最新版是第3版,舊版有1、2兩版
所以這裡可以針對不同版本做不同的更新動作,因為各版更新的都不同
所以可以用switch case分開各版本再對各版本做不同的更新動作(如上面程式碼)
(2)更新資料庫不止可以下ALTER的SQL指令而已,因為資料本身是存在的
只要不下Drop,所以可以用Cursor cursor = db.rawQuery把資料撈出來做變更
我個人是把資料撈出來做日期格式的變更,最後再下ALTER新增欄位
注意看程式碼中1版是ALTER了4個欄位,2版是ALTER了3個欄位
所以如果你是放上google play上是要針對每個版本做不同的更新
因為你不知道下載者有沒有即時去更新你的應用程式,所以基本上要保留資料
就要這樣寫把之前的版本做不同的更新,這樣才能確保每一個版本都能更新
到最新的版本而不會出錯。
以上說明希望能幫助你對Android的資料庫有了進一步的了解,謝謝。
不知道您會不會遇到比方說我版本是第8版
回覆刪除然後到第9版新增一個欄位後也是可以執行
到了第10版想說砍到整個資料庫的東西
但是在第10版他卻會說沒有我第九版的新增欄位
因次都會出錯!!
所以在第十一版又重複ALTER最後一個欄位才不會出錯
不知道有沒有遇過這種問題
會出錯的應該是從第8版要Update的
刪除所以你要update第10版時應該要寫兩個版本的判斷
如果是第8版來的就要先做新增一個欄位
如果是第9版來的就不用
重點在ALTER欄位當然都不會出錯,因為最多就沒有ALTER到欄位而已
只有在寫入資料時會出錯而已,在升級資料庫版本時是不會出錯的
不過如果要砍資料庫的東西,當然沒有那個欄位時要砍就一定會馬上出錯