天天看點

Android 資料庫更新解決方案

[-]

總體思路

得到資料庫表的列名

資料庫更新的意義

定義資料庫版本

如何寫更新邏輯

注意

如何保證資料不丢失

sql語句

請考慮如下情況:

在資料庫更新時,不同版本的資料庫,他們定義的表結構完全可能是不一樣的,比如v1.0的表a有10個column,而在v1.1的表a有12個colum,在更新時,表a增加了兩列,此時我們應該怎麼做呢。

1,将表a重命名,改了a_temp。

2,建立新表a。

3,将表a_temp的資料插入到表a。

下面代碼列出了更新表的實作,upgradetables,給定表名,更新的列名,就可以實作資料庫表的更新。

[java]

view plaincopy

/** 

 * upgrade tables. in this method, the sequence is: 

 * <b> 

 * <p>[1] rename the specified table as a temporary table. 

 * <p>[2] create a new table which name is the specified name. 

 * <p>[3] insert data into the new created table, data from the temporary table. 

 * <p>[4] drop the temporary table. 

 * </b> 

 * 

 * @param db the database. 

 * @param tablename the table name. 

 * @param columns the columns range, format is "cola, colb, colc, ... coln"; 

 */  

protected void upgradetables(sqlitedatabase db, string tablename, string columns)  

{  

    try  

    {  

        db.begintransaction();  

        // 1, rename table.  

        string temptablename = tablename + "_temp";  

        string sql = "alter table " + tablename +" rename to " + temptablename;  

        execsql(db, sql, null);  

        // 2, create table.  

        oncreatetable(db);  

        // 3, load data  

        sql =   "insert into " + tablename +  

                " (" + columns + ") " +  

                " select " + columns + " from " + temptablename;  

        // 4, drop the temporary table.  

        execsql(db, "drop table if exists " + temptablename, null);  

        db.settransactionsuccessful();  

    }  

    catch (sqlexception e)  

        e.printstacktrace();  

    catch (exception e)  

    finally  

        db.endtransaction();  

}  

我們可以通過sql表得到表的列名。 這裡需要注意的一點,int columnindex = c.getcolumnindex("name"); 這裡根據name去取得index。 

protected string[] getcolumnnames(sqlitedatabase db, string tablename)  

    string[] columnnames = null;  

    cursor c = null;  

        c = db.rawquery("pragma table_info(" + tablename + ")", null);  

        if (null != c)  

        {  

            int columnindex = c.getcolumnindex("name");  

            if (-1 == columnindex)  

            {  

                return null;  

            }  

            int index = 0;  

            columnnames = new string[c.getcount()];  

            for (c.movetofirst(); !c.isafterlast(); c.movetonext())  

                columnnames[index] = c.getstring(columnindex);  

                index++;  

        }  

        closecursor(c);  

    return columnnames;  

upgradetables方法應該是在onupgrade方法中去調用。

在應用程式開發的過程中,資料庫的更新是一個很重要的組成部分(如果用到了資料庫),因為程式可能會有v1.0,v2.0,當使用者安裝新版本的程式後,必須要保證使用者資料不能丢失,對于資料庫設計,如果發生變更(如多添加一張表,表的字段增加或減少等),那麼我們必須想好資料庫的更新政策。

資料庫的版本是一個整型值,在建立sqliteopenhelper時,會傳入該資料庫的版本,如果傳入的資料庫版本号比資料庫檔案中存儲的版本号大的話,那麼sqliteopenhelper#onupgrade()方法就會被調用,我們的更新應該在該方法中完成。

假如我們開發的程式已經釋出了兩個版本:v1.0,v1.2,我們正在開發v1.3。每一版的資料庫版本号分别是18,19,20。

對于這種情況,我們應該如何實作更新?

使用者的選擇有:                   

1) v1.0 -> v1.3  db 18 -> 20                  

2) v1.1 -> v1.3  db 19 -> 20      

資料庫的每一個版本所代表的資料庫必須是定義好的,比如說v18的資料庫,它可能隻有兩張表tablea和tableb,如果v19要添加一張表tablec,如果v20要修改tablec,那麼每一個版本所對應的資料庫結構如下:

v18  --->  tablea, tableb

v19  --->  tablea, tableb, tablec

v20  --->  tablea, tableb, tablec (變更)

onupgrade()方法的實作如下:

       // pattern for upgrade blocks:  

//  

//    if (upgradeversion == [the database_version you set] - 1){  

//        .. your upgrade logic..  

//        upgradeversion = [the database_version you set]  

//    }  

public void onupgrade(sqlitedatabase db, int oldversion, int newversion)  

    int upgradeversion  = oldversion;  

    if (18 == upgradeversion) {  

        // create table c  

        string sql = "create table ...";  

        db.execsql(sql);  

        upgradeversion = 19;  

    if (20 == upgradeversion) {  

        // modify table c  

        upgradeversion = 20;  

    if (upgradeversion != newversion) {  

        // drop tables  

        db.execsql("drop table if exists " + tablename);  

        // create tables  

        oncreate(db);  

從上面的代碼可以看到,我們在onupgrade()方法中,處理了資料庫版本從18 -> 20的更新過程,這樣做的話,不論使用者從18 -> 20,還是從19 -> 20,最終程式的資料庫都能更新到v20所對應的資料庫結構。  

這是很重要的一部分,假設要更新tablec表,我們建議的做法是:       

1) 将tablec重命名為tablec_temp

       sql語句可以這樣寫:alert table tablec rename to tablec_temp;

2) 建立新的tablec表

3) 将資料從tablec_temp中插入到tablec表中

       sql語句可以這樣寫:insert into tablec (col1, col2, col3) select (col1, col2, col3) from tablec_temp;                

經過這三步,tablec就完成了更新,同時,也保留了原來表中的資料。  

注意:

在onupgrade()方法中,删除表時,注意使用事務處理,使得修改能立即反應到資料庫檔案中。       

由于android是使用開源的sqlite3作為其資料庫,是以,我們在開發資料庫子產品時,一定要注意sqlite3支援哪些關鍵字,函數等,不是所有的關鍵字,sqlite都是支援的。

下面列出了一些參考連結:

sqlite3官方文檔:http://sqlite.org/

Android 資料庫更新解決方案

w3cschool網站:http://www.w3school.com.cn/sql/index.asp/

Android 資料庫更新解決方案

sql語句寫得好壞能直接影響到資料庫的操作。我曾經就遇到過sql語句影響查詢性能,更新3000條記錄,用時30移左右,但在對where條件的字段加上索引後,性能提升到3~4秒。