Android 數據庫升級解決方案
[-]請考慮如下情況:
在數據庫升級時,不同版本的數據庫,他們定義的表結構完全可能是不一樣的,比如V1.0的表A有10個column,而在V1.1的表A有12個colum,在升級時,表A增加了兩列,此時我們應該怎麼做呢。
總體思路
1,將表A重命名,改了A_temp。
2,創建新表A。
3,將表A_temp的數據插入到表A。
下麵代碼列出了更新表的實現,upgradeTables,給定表名,更新的列名,就可以實現數據庫表的更新。
- /**
- * 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;
- execSQL(db, sql, null);
- // 4, Drop the temporary table.
- execSQL(db, "DROP TABLE IF EXISTS " + tempTableName, null);
- db.setTransactionSuccessful();
- }
- catch (SQLException e)
- {
- e.printStackTrace();
- }
- catch (Exception e)
- {
- e.printStackTrace();
- }
- finally
- {
- db.endTransaction();
- }
- }
得到數據庫表的列名
我們可以通過SQL表得到表的列名。 這裏需要注意的一點,int columnIndex = c.getColumnIndex("name"); 這裏根據name去取得index。
- protected String[] getColumnNames(SQLiteDatabase db, String tableName)
- {
- String[] columnNames = null;
- Cursor c = null;
- try
- {
- 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++;
- }
- }
- }
- catch (Exception e)
- {
- e.printStackTrace();
- }
- finally
- {
- closeCursor(c);
- }
- return columnNames;
- }
數據庫升級的意義
在應用程序開發的過程中,數據庫的升級是一個很重要的組成部分(如果用到了數據庫),因為程序可能會有V1.0,V2.0,當用戶安裝新版本的程序後,必須要保證用戶數據不能丟失,對於數據庫設計,如果發生變更(如多添加一張表,表的字段增加或減少等),那麼我們必須想好數據庫的更新策略。
1,定義數據庫版本
數據庫的版本是一個整型值,在創建SQLiteOpenHelper時,會傳入該數據庫的版本,如果傳入的數據庫版本號比數據庫文件中存儲的版本號大的話,那麼SQLiteOpenHelper#onUpgrade()方法就會被調用,我們的升級應該在該方法中完成。
2,如何寫升級邏輯
假如我們開發的程序已經發布了兩個版本: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
3,注意
數據庫的每一個版本所代表的數據庫必須是定義好的,比如說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所對應的數據庫結構。
4,如何保證數據不丟失
這是很重要的一部分,假設要更新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()方法中,刪除表時,注意使用事務處理,使得修改能立即反應到數據庫文件中。
SQL語句
由於Android是使用開源的SQLite3作為其數據庫,所以,我們在開發數據庫模塊時,一定要注意SQLite3支持哪些關鍵字,函數等,不是所有的關鍵字,SQLite都是支持的。
下麵列出了一些參考鏈接:
SQLite3官方文檔:https://sqlite.org/
W3CSchool網站:https://www.w3school.com.cn/sql/index.asp/
SQL語句寫得好壞能直接影響到數據庫的操作。我曾經就遇到過SQL語句影響查詢性能,更新3000條記錄,用時30移左右,但在對WHERE條件的字段加上索引後,性能提升到3~4秒。
最後更新:2017-04-03 08:26:26