Greendao 升級 資料丟失 資料遷移
最近更新:2018年3月6日18:47:26
因為資料庫新增欄位,所以我就把 src中的schemaVersion +1,簽完名之後測試,發現以前所有資料丟失了,頓時一身冷汗,太可怕了。之後在網上找資料發現DaoMaster中onUpgrade中 程式碼是:
dropAllTables(db, true); onCreate(db);所以每次升級,都是先把所有表都刪了,重新建立,這怎麼可以,侮辱Greendao,怎麼這樣設計,我升級資料庫,你至少給我選擇啊,到底是刪除還是保留上一次資料。
沒有辦法,繼續找資料,解決的辦法無非是:把舊錶改為臨時表,建立新表,臨時表資料寫入新表,刪除臨時表。我又不是太懂資料庫,懂思路是懂了,但是要怎麼下手?好吧,繼續找資料。
正題:
1.把MyApplication中初始化資料庫 改成
DaoMaster.DevOpenHelper mHelper = new MigrationHelper(this, "mydatabase.db", null);
2.編寫 MigrationHelper類
public class MigrationHelper extends DaoMaster.DevOpenHelper { private final String TAG="MigrationHelper"; public MigrationHelper(Context context, String name....表示你所有的表。) { super(context, name); } public MigrationHelper(Context context, String name, SQLiteDatabase.CursorFactory factory) { super(context, name, factory); } @Override public void onUpgrade(Database db, int oldVersion, int newVersion) { LogUtil.i(TAG,"oldVersion="+oldVersion+",newVersion="+newVersion); if (newVersion > oldVersion) { new UpgradeHelper().migrate(db, AdcDao.class, ..........SettingDao.class, WifiDao.class); } } }
3.編寫 UpgradeHelper 類
public class UpgradeHelper { private final String TAG = "UpgradeHelper"; private static final String CONVERSION_CLASS_NOT_FOUND_EXCEPTION = "MIGRATION HELPER - CLASS DOESN'T MATCH WITH THE CURRENT PARAMETERS"; private static MigrationHelper instance; public static MigrationHelper getInstance() { if (instance == null) { instance = new MigrationHelper(MyApplacition.getInstances(), "mydatabase.db"); } return instance; } public void migrate(final Database db, final Class<? extends AbstractDao<?, ?>>... daoClasses) { LogUtil.i(TAG, "1111"); generateTempTables(db, daoClasses); LogUtil.i(TAG, "2222"); DaoMaster.dropAllTables(db, true); LogUtil.i(TAG, "3333"); DaoMaster.createAllTables(db, false); LogUtil.i(TAG, "4444"); restoreData(db, daoClasses); } private void generateTempTables(Database db, Class<? extends AbstractDao<?, ?>>... daoClasses) { for (int i = 0; i < daoClasses.length; i++) { try { DaoConfig daoConfig = new DaoConfig(db, daoClasses[i]); String divider = ""; String tableName = daoConfig.tablename; String tempTableName = daoConfig.tablename.concat("_TEMP"); ArrayList<String> properties = new ArrayList<>(); StringBuilder createTableStringBuilder = new StringBuilder(); createTableStringBuilder.append("CREATE TABLE ").append(tempTableName).append(" ("); for (int j = 0; j < daoConfig.properties.length; j++) { String columnName = daoConfig.properties[j].columnName; if (getColumns(db, tableName).contains(columnName)) { properties.add(columnName); String type = null; try { type = getTypeByClass(daoConfig.properties[j].type); } catch (Exception exception) { exception.printStackTrace(); } createTableStringBuilder.append(divider).append(columnName).append(" ").append(type); if (daoConfig.properties[j].primaryKey) { createTableStringBuilder.append(" PRIMARY KEY"); } divider = ","; } } createTableStringBuilder.append(");"); db.execSQL(createTableStringBuilder.toString()); StringBuilder insertTableStringBuilder = new StringBuilder(); insertTableStringBuilder.append("INSERT INTO ").append(tempTableName).append(" ("); insertTableStringBuilder.append(TextUtils.join(",", properties)); insertTableStringBuilder.append(") SELECT "); insertTableStringBuilder.append(TextUtils.join(",", properties)); insertTableStringBuilder.append(" FROM ").append(tableName).append(";"); db.execSQL(insertTableStringBuilder.toString()); } catch (Exception e) { e.printStackTrace(); } finally { continue; } } } private void restoreData(Database db, Class<? extends AbstractDao<?, ?>>... daoClasses) { for (int i = 0; i < daoClasses.length; i++) { try { DaoConfig daoConfig = new DaoConfig(db, daoClasses[i]); String tableName = daoConfig.tablename; String tempTableName = daoConfig.tablename.concat("_TEMP"); LogUtil.i(TAG, "tableName=" + tableName); ArrayList<String> properties = new ArrayList(); for (int j = 0; j < daoConfig.properties.length; j++) { String columnName = daoConfig.properties[j].columnName; if (getColumns(db, tempTableName).contains(columnName)) { properties.add(columnName); } } StringBuilder insertTableStringBuilder = new StringBuilder(); insertTableStringBuilder.append("INSERT INTO ").append(tableName).append(" ("); insertTableStringBuilder.append(TextUtils.join(",", properties)); insertTableStringBuilder.append(") SELECT "); insertTableStringBuilder.append(TextUtils.join(",", properties)); insertTableStringBuilder.append(" FROM ").append(tempTableName).append(";"); StringBuilder dropTableStringBuilder = new StringBuilder(); dropTableStringBuilder.append("DROP TABLE ").append(tempTableName); db.execSQL(insertTableStringBuilder.toString()); db.execSQL(dropTableStringBuilder.toString()); } catch (Exception e) { e.printStackTrace(); } finally { continue; } } }
private String getTypeByClass(Class<?> type) throws Exception { if (type.equals(String.class)) { return "TEXT"; } if (type.equals(Long.class) || type.equals(long.class)|| type.equals(Integer.class) || type.equals(int.class)|| type.equals(byte.class)||type.equals(Byte.class)|| type.equals(short.class)||type.equals(Short.class)) { return "INTEGER"; } if (type.equals(Boolean.class)||type.equals(boolean.class)) { return "BOOLEAN"; } if (type.equals(Double.class)||type.equals(double.class) ||type.equals(float.class)||type.equals(Float.class)){ return "REAL"; } if(type.equals(byte[].class)){ return "BLOB"; } Exception exception = new Exception(CONVERSION_CLASS_NOT_FOUND_EXCEPTION.concat(" - Class: ").concat(type.toString())); exception.printStackTrace(); throw exception; }
private static List<String> getColumns(Database db, String tableName) {
List<String> columns = new ArrayList<>();
Cursor cursor = null;
try {
cursor = db.rawQuery("SELECT * FROM " + tableName + " limit 1", null);
if (cursor != null) {
columns = new ArrayList<>(Arrays.asList(cursor.getColumnNames()));
}
} catch (Exception e) {
Log.v(tableName, e.getMessage(), e);
e.printStackTrace();
} finally {
if (cursor != null)
cursor.close();
}
return columns;
}
}
你再試一試,發現是不是可以了,哦記住schemaVersion 要加1。
我試過 增加欄位和 新增表 都是可以的,刪除我沒有試過。
注意:getTypeByClass中一定注意寫好對應的資料型別,這個跟SQL不一樣,你看我的,我寫了一部分,但是你自己操作比較好,我告訴你方法。在DaoMaster中找到creatAllTable方法,有多少個表就有多少類似xxxDao.creatTable(db,ifNotExists)。進入createTable可以看到
db.execSQL("CREATE TABLE " + constraint + "\"BUS_EVENT__REPORT\" (" + // "\"_id\" INTEGER PRIMARY KEY AUTOINCREMENT ," + // 0: id "\"mode\" INTEGER NOT NULL ," + // 1: mode "\"tel\" TEXT," + // 2: tel
這裡你就可以看到 叫mode的欄位是INTERGET 叫tel的欄位型別是TEXT。
所以在getTypeByClass中也模仿著寫,你懂了吧。
OK!