├── MigrationHelper.java ├── MySQLiteOpenHelper.java └── README.md /MigrationHelper.java: -------------------------------------------------------------------------------- 1 | package com.min.mygreendao; 2 | 3 | import android.database.Cursor; 4 | import android.database.SQLException; 5 | import android.database.sqlite.SQLiteDatabase; 6 | import android.support.annotation.NonNull; 7 | import android.text.TextUtils; 8 | import android.util.Log; 9 | 10 | import org.greenrobot.greendao.AbstractDao; 11 | import org.greenrobot.greendao.database.Database; 12 | import org.greenrobot.greendao.database.StandardDatabase; 13 | import org.greenrobot.greendao.internal.DaoConfig; 14 | 15 | import java.lang.ref.WeakReference; 16 | import java.lang.reflect.InvocationTargetException; 17 | import java.lang.reflect.Method; 18 | import java.util.ArrayList; 19 | import java.util.Arrays; 20 | import java.util.List; 21 | 22 | /** 23 | * 24 | * please call {@link #migrate(SQLiteDatabase, Class[])} or {@link #migrate(Database, Class[])} 25 | * 26 | */ 27 | public final class MigrationHelper { 28 | 29 | public static boolean DEBUG = false; 30 | private static String TAG = "MigrationHelper"; 31 | private static final String SQLITE_MASTER = "sqlite_master"; 32 | private static final String SQLITE_TEMP_MASTER = "sqlite_temp_master"; 33 | 34 | private static WeakReference weakListener; 35 | 36 | public interface ReCreateAllTableListener{ 37 | void onCreateAllTables(Database db, boolean ifNotExists); 38 | void onDropAllTables(Database db, boolean ifExists); 39 | } 40 | 41 | public static void migrate(SQLiteDatabase db, Class>... daoClasses) { 42 | printLog("【The Old Database Version】" + db.getVersion()); 43 | Database database = new StandardDatabase(db); 44 | migrate(database, daoClasses); 45 | } 46 | 47 | public static void migrate(SQLiteDatabase db, ReCreateAllTableListener listener, Class>... daoClasses) { 48 | weakListener = new WeakReference<>(listener); 49 | migrate(db, daoClasses); 50 | } 51 | 52 | public static void migrate(Database database, ReCreateAllTableListener listener, Class>... daoClasses) { 53 | weakListener = new WeakReference<>(listener); 54 | migrate(database, daoClasses); 55 | } 56 | 57 | public static void migrate(Database database, Class>... daoClasses) { 58 | printLog("【Generate temp table】start"); 59 | generateTempTables(database, daoClasses); 60 | printLog("【Generate temp table】complete"); 61 | 62 | ReCreateAllTableListener listener = null; 63 | if (weakListener != null) { 64 | listener = weakListener.get(); 65 | } 66 | 67 | if (listener != null) { 68 | listener.onDropAllTables(database, true); 69 | printLog("【Drop all table by listener】"); 70 | listener.onCreateAllTables(database, false); 71 | printLog("【Create all table by listener】"); 72 | } else { 73 | dropAllTables(database, true, daoClasses); 74 | createAllTables(database, false, daoClasses); 75 | } 76 | printLog("【Restore data】start"); 77 | restoreData(database, daoClasses); 78 | printLog("【Restore data】complete"); 79 | } 80 | 81 | private static void generateTempTables(Database db, Class>... daoClasses) { 82 | for (int i = 0; i < daoClasses.length; i++) { 83 | String tempTableName = null; 84 | 85 | DaoConfig daoConfig = new DaoConfig(db, daoClasses[i]); 86 | String tableName = daoConfig.tablename; 87 | if (!isTableExists(db, false, tableName)) { 88 | printLog("【New Table】" + tableName); 89 | continue; 90 | } 91 | try { 92 | tempTableName = daoConfig.tablename.concat("_TEMP"); 93 | StringBuilder dropTableStringBuilder = new StringBuilder(); 94 | dropTableStringBuilder.append("DROP TABLE IF EXISTS ").append(tempTableName).append(";"); 95 | db.execSQL(dropTableStringBuilder.toString()); 96 | 97 | StringBuilder insertTableStringBuilder = new StringBuilder(); 98 | insertTableStringBuilder.append("CREATE TEMPORARY TABLE ").append(tempTableName); 99 | insertTableStringBuilder.append(" AS SELECT * FROM ").append(tableName).append(";"); 100 | db.execSQL(insertTableStringBuilder.toString()); 101 | printLog("【Table】" + tableName +"\n ---Columns-->"+getColumnsStr(daoConfig)); 102 | printLog("【Generate temp table】" + tempTableName); 103 | } catch (SQLException e) { 104 | Log.e(TAG, "【Failed to generate temp table】" + tempTableName, e); 105 | } 106 | } 107 | } 108 | 109 | private static boolean isTableExists(Database db, boolean isTemp, String tableName) { 110 | if (db == null || TextUtils.isEmpty(tableName)) { 111 | return false; 112 | } 113 | String dbName = isTemp ? SQLITE_TEMP_MASTER : SQLITE_MASTER; 114 | String sql = "SELECT COUNT(*) FROM " + dbName + " WHERE type = ? AND name = ?"; 115 | Cursor cursor=null; 116 | int count = 0; 117 | try { 118 | cursor = db.rawQuery(sql, new String[]{"table", tableName}); 119 | if (cursor == null || !cursor.moveToFirst()) { 120 | return false; 121 | } 122 | count = cursor.getInt(0); 123 | } catch (Exception e) { 124 | e.printStackTrace(); 125 | } finally { 126 | if (cursor != null) 127 | cursor.close(); 128 | } 129 | return count > 0; 130 | } 131 | 132 | 133 | private static String getColumnsStr(DaoConfig daoConfig) { 134 | if (daoConfig == null) { 135 | return "no columns"; 136 | } 137 | StringBuilder builder = new StringBuilder(); 138 | for (int i = 0; i < daoConfig.allColumns.length; i++) { 139 | builder.append(daoConfig.allColumns[i]); 140 | builder.append(","); 141 | } 142 | if (builder.length() > 0) { 143 | builder.deleteCharAt(builder.length() - 1); 144 | } 145 | return builder.toString(); 146 | } 147 | 148 | 149 | private static void dropAllTables(Database db, boolean ifExists, @NonNull Class>... daoClasses) { 150 | reflectMethod(db, "dropTable", ifExists, daoClasses); 151 | printLog("【Drop all table by reflect】"); 152 | } 153 | 154 | private static void createAllTables(Database db, boolean ifNotExists, @NonNull Class>... daoClasses) { 155 | reflectMethod(db, "createTable", ifNotExists, daoClasses); 156 | printLog("【Create all table by reflect】"); 157 | } 158 | 159 | /** 160 | * dao class already define the sql exec method, so just invoke it 161 | */ 162 | private static void reflectMethod(Database db, String methodName, boolean isExists, @NonNull Class>... daoClasses) { 163 | if (daoClasses.length < 1) { 164 | return; 165 | } 166 | try { 167 | for (Class cls : daoClasses) { 168 | Method method = cls.getDeclaredMethod(methodName, Database.class, boolean.class); 169 | method.invoke(null, db, isExists); 170 | } 171 | } catch (NoSuchMethodException e) { 172 | e.printStackTrace(); 173 | } catch (InvocationTargetException e) { 174 | e.printStackTrace(); 175 | } catch (IllegalAccessException e) { 176 | e.printStackTrace(); 177 | } 178 | } 179 | 180 | private static void restoreData(Database db, Class>... daoClasses) { 181 | for (int i = 0; i < daoClasses.length; i++) { 182 | DaoConfig daoConfig = new DaoConfig(db, daoClasses[i]); 183 | String tableName = daoConfig.tablename; 184 | String tempTableName = daoConfig.tablename.concat("_TEMP"); 185 | 186 | if (!isTableExists(db, true, tempTableName)) { 187 | continue; 188 | } 189 | 190 | try { 191 | // get all columns from tempTable, take careful to use the columns list 192 | List newTableInfos = TableInfo.getTableInfo(db, tableName); 193 | List tempTableInfos = TableInfo.getTableInfo(db, tempTableName); 194 | ArrayList selectColumns = new ArrayList<>(newTableInfos.size()); 195 | ArrayList intoColumns = new ArrayList<>(newTableInfos.size()); 196 | for (TableInfo tableInfo : tempTableInfos) { 197 | if (newTableInfos.contains(tableInfo)) { 198 | String column = '`' + tableInfo.name + '`'; 199 | intoColumns.add(column); 200 | selectColumns.add(column); 201 | } 202 | } 203 | // NOT NULL columns list 204 | for (TableInfo tableInfo : newTableInfos) { 205 | if (tableInfo.notnull && !tempTableInfos.contains(tableInfo)) { 206 | String column = '`' + tableInfo.name + '`'; 207 | intoColumns.add(column); 208 | 209 | String value; 210 | if (tableInfo.dfltValue != null) { 211 | value = "'" + tableInfo.dfltValue + "' AS "; 212 | } else { 213 | value = "'' AS "; 214 | } 215 | selectColumns.add(value + column); 216 | } 217 | } 218 | 219 | if (intoColumns.size() != 0) { 220 | StringBuilder insertTableStringBuilder = new StringBuilder(); 221 | insertTableStringBuilder.append("REPLACE INTO ").append(tableName).append(" ("); 222 | insertTableStringBuilder.append(TextUtils.join(",", intoColumns)); 223 | insertTableStringBuilder.append(") SELECT "); 224 | insertTableStringBuilder.append(TextUtils.join(",", selectColumns)); 225 | insertTableStringBuilder.append(" FROM ").append(tempTableName).append(";"); 226 | db.execSQL(insertTableStringBuilder.toString()); 227 | printLog("【Restore data】 to " + tableName); 228 | } 229 | StringBuilder dropTableStringBuilder = new StringBuilder(); 230 | dropTableStringBuilder.append("DROP TABLE ").append(tempTableName); 231 | db.execSQL(dropTableStringBuilder.toString()); 232 | printLog("【Drop temp table】" + tempTableName); 233 | } catch (SQLException e) { 234 | Log.e(TAG, "【Failed to restore data from temp table 】" + tempTableName, e); 235 | } 236 | } 237 | } 238 | 239 | private static List getColumns(Database db, String tableName) { 240 | List columns = null; 241 | Cursor cursor = null; 242 | try { 243 | cursor = db.rawQuery("SELECT * FROM " + tableName + " limit 0", null); 244 | if (null != cursor && cursor.getColumnCount() > 0) { 245 | columns = Arrays.asList(cursor.getColumnNames()); 246 | } 247 | } catch (Exception e) { 248 | e.printStackTrace(); 249 | } finally { 250 | if (cursor != null) 251 | cursor.close(); 252 | if (null == columns) 253 | columns = new ArrayList<>(); 254 | } 255 | return columns; 256 | } 257 | 258 | private static void printLog(String info){ 259 | if(DEBUG){ 260 | Log.d(TAG, info); 261 | } 262 | } 263 | 264 | private static class TableInfo { 265 | int cid; 266 | String name; 267 | String type; 268 | boolean notnull; 269 | String dfltValue; 270 | boolean pk; 271 | 272 | @Override 273 | public boolean equals(Object o) { 274 | return this == o 275 | || o != null 276 | && getClass() == o.getClass() 277 | && name.equals(((TableInfo) o).name); 278 | } 279 | 280 | @Override 281 | public String toString() { 282 | return "TableInfo{" + 283 | "cid=" + cid + 284 | ", name='" + name + '\'' + 285 | ", type='" + type + '\'' + 286 | ", notnull=" + notnull + 287 | ", dfltValue='" + dfltValue + '\'' + 288 | ", pk=" + pk + 289 | '}'; 290 | } 291 | 292 | private static List getTableInfo(Database db, String tableName) { 293 | String sql = "PRAGMA table_info(" + tableName + ")"; 294 | printLog(sql); 295 | Cursor cursor = db.rawQuery(sql, null); 296 | if (cursor == null) 297 | return new ArrayList<>(); 298 | 299 | TableInfo tableInfo; 300 | List tableInfos = new ArrayList<>(); 301 | while (cursor.moveToNext()) { 302 | tableInfo = new TableInfo(); 303 | tableInfo.cid = cursor.getInt(0); 304 | tableInfo.name = cursor.getString(1); 305 | tableInfo.type = cursor.getString(2); 306 | tableInfo.notnull = cursor.getInt(3) == 1; 307 | tableInfo.dfltValue = cursor.getString(4); 308 | tableInfo.pk = cursor.getInt(5) == 1; 309 | tableInfos.add(tableInfo); 310 | // printLog(tableName + ":" + tableInfo); 311 | } 312 | cursor.close(); 313 | return tableInfos; 314 | } 315 | } 316 | } -------------------------------------------------------------------------------- /MySQLiteOpenHelper.java: -------------------------------------------------------------------------------- 1 | package com.min.mygreendao; 2 | 3 | import android.content.Context; 4 | import android.database.sqlite.SQLiteDatabase; 5 | 6 | 7 | import com.min.mygreendao.db.gen.DaoMaster; 8 | import com.min.mygreendao.db.gen.TestDao; 9 | import com.min.mygreendao.db.gen.UserDao; 10 | 11 | import org.greenrobot.greendao.database.Database; 12 | 13 | /** 14 | * Created by Administrator on 2017/9/13. 15 | * 16 | * @des 数据库升级 17 | */ 18 | public class MySQLiteOpenHelper extends DaoMaster.OpenHelper { 19 | public MySQLiteOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory) { 20 | super(context, name, factory); 21 | } 22 | @Override 23 | public void onUpgrade(Database db, int oldVersion, int newVersion) { 24 | MigrationHelper.migrate(db, new MigrationHelper.ReCreateAllTableListener() { 25 | 26 | @Override 27 | public void onCreateAllTables(Database db, boolean ifNotExists) { 28 | DaoMaster.createAllTables(db, ifNotExists); 29 | } 30 | 31 | @Override 32 | public void onDropAllTables(Database db, boolean ifExists) { 33 | DaoMaster.dropAllTables(db, ifExists); 34 | } 35 | }, UserDao.class,TestDao.class);//, UserDao.class 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MigrationHelper 2 | GreenDao升级使用的一个java类 3 | ### 使用说明地址https://www.jianshu.com/p/84bde36678d2 4 | --------------------------------------------------------------------------------