[-]
總體思路
得到資料庫表的列名
資料庫更新的意義
定義資料庫版本
如何寫更新邏輯
注意
如何保證資料不丢失
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/
w3cschool網站:http://www.w3school.com.cn/sql/index.asp/
sql語句寫得好壞能直接影響到資料庫的操作。我曾經就遇到過sql語句影響查詢性能,更新3000條記錄,用時30移左右,但在對where條件的字段加上索引後,性能提升到3~4秒。