編輯:關於Android編程
在上一篇文章中,我們學習了LitePal的基本用法,體驗了使用框架來進行創建表操作的便利。然而大家都知道,創建表只是數據庫操作中最基本的一步而已,我們在一開始創建的表結構,隨著需求的變更,到了後期是極有可能需要修改的。因此,升級表的操作對於任何一個項目也是至關重要的,那麼今天我們就一起來學習一下,在Android傳統開發當中升級表的方式,以及使用LitePal來進行升級表操作的用法。如果你還沒有看過前一篇文章,建議先去參考一下 Android數據庫高手秘籍(二)——創建表和LitePal的基本用法 。
上一篇文章中我們借助MySQLiteHelper已經創建好了news這張表,這也是demo.db這個數據庫的第一個版本。然而,現在需求發生了變更,我們的軟件除了能看新聞之外,還應該允許用戶評論,所以這時就需要對數據庫進行升級,添加一個comment表。
該怎麼做呢?添加一個comment表的建表語句,然後在onCreate()方法中去執行它?沒錯,這樣的話,兩張表就會同時創建了,代碼如下所示:
public class MySQLiteHelper extends SQLiteOpenHelper { public static final String CREATE_NEWS = create table news ( + id integer primary key autoincrement, + title text, + content text, + publishdate integer, + commentcount integer); public static final String CREATE_COMMENT = create table comment ( + id integer primary key autoincrement, + content text); public MySQLiteHelper(Context context, String name, CursorFactory factory, int version) { super(context, name, factory, version); } @Override public void onCreate(SQLiteDatabase db) { db.execSQL(CREATE_NEWS); db.execSQL(CREATE_COMMENT); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { } }這對於第一次安裝我們軟件的用戶來說是完全可以正常工作的,但是如果有的用戶已經安裝過上一版的軟件,那麼很遺憾,comment表是創建不出來的,因為之前數據庫就已經創建過了,onCreate()方法是不會重新執行的。
對於這種情況我們就要用升級的方式來解決了,看到MySQLiteHelper構造方法中的第四個參數了嗎,這個就是數據庫版本號的標識,每當版本號增加的時候就會調用onUpgrade()方法,我們只需要在這裡處理升級表的操作就行了。比較簡單粗暴的方式是將數據庫中現有的所有表都刪除掉,然後重新創建,代碼如下所示:
public class MySQLiteHelper extends SQLiteOpenHelper { ...... @Override public void onCreate(SQLiteDatabase db) { db.execSQL(CREATE_NEWS); db.execSQL(CREATE_COMMENT); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { db.execSQL(drop table if exists news); onCreate(db); } }可以看到,當數據庫升級的時候,我們先把news表刪除掉,然後重新執行了一次onCreate()方法,這樣就保證數據庫中的表都是最新的了。
但是,如果news表中本來已經有數據了,使用這種方式升級的話,就會導致表中的數據全部丟失,所以這並不是一種值得推薦的升級方法。那麼更好的升級方法是什麼樣的呢?這就稍微有些復雜了,需要在onUpgrade()方法中根據版本號加入具體的升級邏輯,我們來試試來吧。比如之前的數據庫版本號是1,那麼在onUpgrade()方法中就可以這樣寫:
public class MySQLiteHelper extends SQLiteOpenHelper { ...... @Override public void onCreate(SQLiteDatabase db) { db.execSQL(CREATE_NEWS); db.execSQL(CREATE_COMMENT); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { switch (oldVersion) { case 1: db.execSQL(CREATE_COMMENT); default: } } }可以看到,這裡在onUpgrade()方法中加入了一個switch判斷,如果oldVersion等於1,就再創建一個comment表。現在只需要調用如下代碼,表就可以得到創建或升級了:
SQLiteOpenHelper dbHelper = new MySQLiteHelper(this, demo.db, null, 2); SQLiteDatabase db = dbHelper.getWritableDatabase();這裡我們將版本號加1,如果用戶是從舊版本升級過來的,就會新增一個comment表,而如果用戶是直接安裝的新版本,就會在onCreate()方法中把兩個表一起創建了。
OK,現在軟件的第二版本也發布出去了,可是就在發布不久之後,突然發現comment表中少了一個字段,我們並沒有記錄評論發布的時間。沒辦法,只好在第三版中修復這個問題了,那我們該怎麼樣去添加這個字段呢?主要需要修改comment表的建表語句,以及onUpgrade()方法中的邏輯,代碼如下所示:
public class MySQLiteHelper extends SQLiteOpenHelper { ...... public static final String CREATE_COMMENT = create table comment ( + id integer primary key autoincrement, + content text, + publishdate integer); ...... @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { switch (oldVersion) { case 1: db.execSQL(CREATE_COMMENT); case 2: db.execSQL(alter table comment add column publishdate integer); default: } } }可以看到,在建表語句當中我們新增了publishdate這一列,這樣當執行onCreate()方法去創建表的時候,comment表中就會有這一列了。那麼如果是從舊版本升級過來的呢?也沒有問題,我們在onUpgrade()方法中已經把升級邏輯都處理好了,當oldVersion等於2的時候,會執行alter語句來添加publishdate這一列。現在調用以下代碼來創建或升級數據庫:
SQLiteOpenHelper dbHelper = new MySQLiteHelper(this, demo.db, null, 3); SQLiteDatabase db = dbHelper.getWritableDatabase();將數據庫版本號設置成3,這樣就可以保證數據庫中的表又是最新的了。
這裡我們要注意一個細節,switch中每一個case的最後都是沒有使用break的,為什麼要這麼做呢?這是為了保證在跨版本升級的時候,每一次的數據庫修改都能被全部執行到。比如用戶當前是從第二版程序升級到第三版程序的,那麼case 2中的邏輯就會執行。而如果用戶是直接從第一版程序升級到第三版程序的,那麼case 1和case 2中的邏輯都會執行。使用這種方式來維護數據庫的升級,不管版本怎樣更新,都可以保證數據庫的表結構是最新的,而且表中的數據也完全不會丟失了。
現在我們已經學習了新增表和新增列這兩種升級方式,那麼如果是某張表中的某一列已經沒有用了,我想把這一列刪除掉該怎麼寫呢?很遺憾,SQLite並不支持刪除列的功能,對於這情況,多數軟件采取的作法是無視它,反正以後也用不到它了,留著也占不了什麼空間,所以針對於這種需求,確實沒什麼簡單的解決辦法。
這大概就是傳統開發當中升級數據庫表的方式了,雖說能寫出這樣的代碼表示你已經對數據庫的升級操作理解的比較清楚了,但隨著版本越來越多,onUpgrade()方法中的邏輯也會變得愈發復雜,稍微一不留神,也許就會產生錯誤。因此,如果能讓代碼自動控制升級邏輯,而不是由人工來管理,那就是再好不過了,那麼下面我們就來學習一下怎樣使用LitePal來進行升級表的操作。
通過上一篇文章的學習,我們已經知道LitePal是一款ORM模式的框架了,已經熟悉創建表流程的你,相信對於升級表也一定會輕車熟路的。那麼為了模仿傳統升級表方式中的需求,現在我們也需要創建一張comment表。第一步該怎麼辦呢?相信你也許早就已經猜到了,那當然是先創建一個Comment類了,如下所示:
package com.example.databasetest.model; public class Comment { private int id; private String content; // 自動生成get、set方法 ... }OK,Comment類中有id和content這兩個字段,也就意味著comment表中會有id和content這兩列。
接著修改litepal.xml中的配置,在映射列表中新增Cooment類,並將版本號加1,如下所示:
沒錯,就是這麼簡單,僅僅兩步,升級的操作就已經完成了,現在我們只需要操作一下數據庫,comment表就會自動生成了,如下所示:
SQLiteDatabase db = Connector.getDatabase();那麼我們還是通過.table命令來查看一下結果,如下圖所示:
OK,comment表已經出來了,那麼再通過pragma命令來查看一下它的表結構吧:
沒有問題,comment表中目前有id和content這兩列,和Comment模型類中的字段是保持一致的。
那麼現在又來了新的需求,需要在comment表中添加一個publishdate列,該怎麼辦呢?不用懷疑,跟著你的直覺走,相信你已經猜到應該在Comment類中添加這樣一個字段了吧,如下所示:
public class Comment { private int id; private String content; private Date publishDate; // 自動生成get、set方法 ... }然後呢?剩下的操作已經非常簡單了,只需要在litepal.xml中對版本號加1就行了,如下所示:
這樣當我們下一次操作數據庫的時候,publishdate列就應該會自動添加到comment表中。調用Connector.getDatabase()方法,然後重新查詢comment表結構,如下所示:...
可以看到,publishdate這一列確實已經成功添加到comment表中了。
通過這兩種升級方式的對比,相信你已經充分體會到了使用LitePal進行升級表操作所帶來的便利了吧。我們不需要去編寫任何與升級相關的邏輯,也不需要關心程序是從哪個版本升級過來的,唯一要做的就是確定好最新的Model結構是什麼樣的,然後將litepal.xml中的版本號加1,所有的升級邏輯就都會自動完成了。LitePal確實將數據庫表的升級操作變得極度簡單,使很多程序員可以從維護數據庫表升級的困擾中解脫出來。
然而,LitePal卻明顯做到了更好。前面我們提到過關於刪除列的問題,最終的結論是無法解決,因為SQLite是不支持刪除列的命令的。但是如果使用LitePal,這一問題就可以簡單地解決掉,比如說publishdate這一列我們又不想要了,那麼只需要在Comment類中把它刪除掉,然後將版本號加1,下次操作數據庫的時候這個列就會不見了。
那麼有的朋友可能會問了,不是說SQLite不支持刪除列的命令嗎?那LitePal又是怎樣做到的呢?其實LitePal並沒有刪除任何一列,它只是先將comment表重命名成一個臨時表,然後根據最新的Comment類的結構生成一個新的comment表,再把臨時表中除了publishdate之外的數據復制到新的表中,最後把臨時表刪掉。因此,看上去的效果好像是做到了刪除列的功能。
這也是使用框架的好處,如果沒有框架的幫助,我們顯然不會為了刪除一個列而大廢周章地去寫這麼多的代碼,而使用框架的話,具體的實現邏輯我們已經不用再關心,只需要控制好模型類的數據結構就可以了。
另外,如果你想刪除某一張表的話,操作也很簡單,在litepal.xml中的映射列表中將相應的類刪除,表自然也就不存在了。其它的一些升級操作也都是類似的,相信你已經能舉一反三,這裡就不再贅述了。
好了,今天對LitePal的介紹就到這裡吧,下篇文章當中我們會學習使用LitePal來進行表關聯的操作。
一、Android Studio配置SVNAndroid Studio關聯配置SVN很簡單,在Settings裡面,找到Version Control->Subve
Android Studio系列-HelloWorld前言Hello 各位,小巫這裡要記錄一些關於如何使用Android Studio開發Android app,這一篇是
視頻播放方式在Android中播放視頻的方式有兩種:1、使用MediaPlayer結合SurfaceView進行播放。其中通過SurfaceView顯示視頻的畫面,通過M
很多時候需要先判斷當前用戶的網絡,才會繼續之後的一些處理邏輯。但網絡類型獲取這一塊,我用我自己的的手機調試時遇到一些問題,這裡記錄一下。一加手機一代,移動4G 網絡,得到