SugarORM 數據庫升級流程源碼分析

在使用SugarORM的時候,有可能在後期的工作中進行數據庫的升級操作。具體的操作參考:http://satyan.github.io/sugar/migration.html
文章鏈接:http://blog.csdn.net/lylddingHFFW/article/details/78230320
記錄:在進行數據庫升級時 注意
1)不支持select等返回數據集結果的語句;
2)在使用alter sql增加表中列的時候,如果Java文件中也增加同樣的字段,則會提示錯誤,增加重複列,後邊的分析會有提到;
3)assets的位置是在src/main/assets/;

public void doUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersion) {
        List<Class> domainClasses = getDomainClasses(context);
        String sql = "select count(*) from sqlite_master where type='table' and name='%s';";

        for (Class domain : domainClasses) {
            String tableName = NamingHelper.toSQLName(domain);
            Cursor c = sqLiteDatabase.rawQuery(String.format(sql, tableName), null);
            //判斷table是否存在,若存在,則檢查table中的columns。
            if (c.moveToFirst() && c.getInt(0) == 0) {
                createTable(domain, sqLiteDatabase);
            } else {
                addColumns(domain, sqLiteDatabase);
            }
        }
        // 執行升級數據庫的sql文件。
        executeSugarUpgrade(sqLiteDatabase, oldVersion, newVersion);
    }

在addColumns中,檢查table中的columns。主要時比對Java文件中的屬性和數據庫 中table中的columns是否一直,若Java文件中有新增加的屬性,則拼接alter table 的sql。

private void addColumns(Class<?> table, SQLiteDatabase sqLiteDatabase) {

        List<Field> fields = ReflectionUtil.getTableFields(table);
        String tableName = NamingHelper.toSQLName(table);
        ArrayList<String> presentColumns = getColumnNames(sqLiteDatabase, tableName);
        ArrayList<String> alterCommands = new ArrayList<>();

        for (Field column : fields) {
            String columnName = NamingHelper.toSQLName(column);
            String columnType = QueryBuilder.getColumnType(column.getType());

            if (column.isAnnotationPresent(Column.class)) {
                Column columnAnnotation = column.getAnnotation(Column.class);
                columnName = columnAnnotation.name();
            }

            if (!presentColumns.contains(columnName)) {
            //拼接 sql 語句
                StringBuilder sb = new StringBuilder("ALTER TABLE ");
                sb.append(tableName).append(" ADD COLUMN ").append(columnName).append(" ").append(columnType);
                if (column.isAnnotationPresent(NotNull.class)) {
                    if (columnType.endsWith(" NULL")) {
                        sb.delete(sb.length() - 5, sb.length());
                    }
                    sb.append(" NOT NULL");
                }

                // Unique is not working on ALTER TABLE
//                if (column.isAnnotationPresent(Unique.class)) {
//                    sb.append(" UNIQUE");
//                }
                alterCommands.add(sb.toString());
            }
        }

        for (String command : alterCommands) {
            Log.i("Sugar", command);
            //執行 拼接的sql 語句。
            sqLiteDatabase.execSQL(command);
        }
    }

executeSugarUpgrade函數中主要執行assets資源文件中的2.sql,3.sql等等。

private boolean executeSugarUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        boolean isSuccess = false;

        try {
        // 拿到assets中的sql文件名
            List<String> files = Arrays.asList(this.context.getAssets().list("sugar_upgrades"));
            Collections.sort(files, new NumberComparator());
            for (String file : files) {
                Log.i(SUGAR, "filename : " + file);

                try {
                    int version = Integer.valueOf(file.replace(".sql", ""));
                     // 只會執行舊版本到新版本之間的sql文件
                    if ((version > oldVersion) && (version <= newVersion)) {
                    //執行sql文件
                        executeScript(db, file);
                        isSuccess = true;
                    }
                } catch (NumberFormatException e) {
                    Log.i(SUGAR, "not a sugar script. ignored." + file);
                }

            }
        } catch (IOException e) {
            Log.e(SUGAR, e.getMessage());
        }

        return isSuccess;
    }

執行sql腳本文件

private void executeScript(SQLiteDatabase db, String file) {
        try {
        //打開sql腳本資源
            InputStream is = this.context.getAssets().open("sugar_upgrades/" + file);
            BufferedReader reader = new BufferedReader(new InputStreamReader(is));
            StringBuilder sb = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                sb.append(line);
            }
            MigrationFileParser migrationFileParser = new MigrationFileParser(sb.toString());
            //以分號;來分割成不同的sql語句
            for(String statement: migrationFileParser.getStatements()){
                Log.i("Sugar script", statement);
                if (!statement.isEmpty()) {
                // 調用SqliteDatebase,來執行
                    db.execSQL(statement);
                }
            }

        } catch (IOException e) {
            Log.e(SUGAR, e.getMessage());
        }

        Log.i(SUGAR, "Script executed");
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章