Author: Lin Guanhong/The Ghost at my Fingertips

The Denver nuggets: https://juejin.cn/user/1785262612681997

Blog: http://www.cnblogs.com/linguanh/

Making: https://github.com/af913337456/

Tencent cloud column: https://cloud.tencent.com/developer/user/1148436/activities

Open source: github.com/af913337456…


This article won’t spend time talking about what greenDao is

When using greenDao as a native ORM framework for online apps, there is always a day when the database tables need to be updated, sooner or later.

directory

  • A situation where something goes wrong

  • A few facts

  • The solution

  • The code is briefly

  • Possible product-level errors

  • Your concerns

A situation in which something goes wrong:

  • Field added, resulting in old table field and new mismatch raisedandroid.database.sqlite.SQLiteExceptionSuch anomalies.
  • The data returned by the server could not match the table and could not be inserted

The first situation will directly cause the APP to flash back, and the second is data mismatch.

A few facts

  • The current 3.+ version of GreenDao, the auto-generated code is upgradedDelete the original table before creating a new one
/** WARNING: Drops all table on Upgrade! Use only during development. */
public static class DevOpenHelper extends OpenHelper {...@Override
    public void onUpgrade(Database db, int oldVersion, int newVersion) {
        Log.i("greenDAO"."Upgrading schema from version " + oldVersion + " to " + newVersion + " by dropping all tables");
        dropAllTables(db, true);  / / delete -- -- -- -- -- (1)onCreate(db); }}Copy the code
  • Automatically generated code files, for examplexxxDao.javaClass changes are regenerated at every build, meaning that personal inline changes are always invalid because they always overwrite yours.
  • The upgrade mode of the database needs to be more compatible with the future, the old data can not be lost

The solution

You can customize an upgrade policy. Ideas for reference

On the basis of the above, the following steps are summarized: (If you do not understand, see the following symbol description)

  • Create a new table that did not previously exist in the old table
  • Create intermediate tables & migrate data from old tables to intermediate tables
  • Delete all the old tables
  • Create all new tables
  • Migrate intermediate table data to new table & delete intermediate table

Corresponding to the steps described above:

  • A -> A + B , old: A , new: B
  • use (A+B) -> create temp (A’+B’) & insert data
  • drop (A+B) , contain old datas
  • create (A+B) , abs empty tables
  • restore data to (A+B) from (A’+B’) then drop (A’+B’)

The code is briefly

Based on the above secondary modification and expansion

  • GreenDaoCompatibleUpdateHelper. Java, as the name implies, compatible with the old table properties greenDao database upgrade, not cause data loss of the old table

    • Expands the ultimate success and failure of the callback
    • Added error log handling
    • Resolved conflicting field name bugs such as DELETE
  • Mygreendaodbhelper. Java custom dbHelper, overloaded onUpgrade

Call example

if (oldVersion < newVersion) {
    Log.e("MyGreenDaoDbHelper"."Perform database upgrade");
    new GreenDaoCompatibleUpdateHelper()
            .setCallBack(
                    new GreenDaoCompatibleUpdateHelper.GreenDaoCompatibleUpdateCallBack() {
                        @Override
                        public void onFinalSuccess(a) {
                            Log.e("MyGreenDaoDbHelper"."Database upgrade ===> successful");
                        }

                        @Override
                        public void onFailedLog(String errorMsg) {
                            Log.e("MyGreenDaoDbHelper"."Upgrade failure log ===>"+errorMsg);
                        }
                    }
            )
            .compatibleUpdate(
                    db,
                    PostBeanDao.class,
                    MatterUserBeanDao.class,
                    PropsBeanDao.class,
                    ChannelChatsBeanDao.class,
                    JoinToChannelReqBeanDao.class
            );
    Log.e("MyGreenDaoDbHelper"."Database upgrade -- done");
}
Copy the code
GreenDaoCompatibleUpdateHelper
public final class GreenDaoCompatibleUpdateHelper {

    public interface GreenDaoCompatibleUpdateCallBack{
        void onFinalSuccess(a);
        void onFailedLog(String errorMsg);
    }

    private static GreenDaoCompatibleUpdateCallBack callBack;

    @SuppressWarnings("all")
    public void compatibleUpdate(SQLiteDatabase sqliteDatabase, Class
        >... daoClasses) {
        StandardDatabase db = new StandardDatabase(sqliteDatabase);
        /** Create a new table that did not exist in the old table */
        if(! generateNewTablesIfNotExists_withNoExchangeData(db, daoClasses))return;
        /** create intermediate table & migrate old table data to intermediate table */
        if(! generateTempTables_withExchangeDataFromOldTable(db, daoClasses))return;
        /** drop all old tables */
        if(! dropAllTables(db,true, daoClasses))                         
            return;
        /** Create all new tables */
        if(! createAllTables_withNoExchangeData(db,false, daoClasses)) 
            return;
        /** delete intermediate table */
        restoreData_fromTempTableToNewTable(db, daoClasses);                     
        if(callBack ! =null)
            callBack.onFinalSuccess();
        callBack = null;
    }

    public GreenDaoCompatibleUpdateHelper setCallBack(GreenDaoCompatibleUpdateCallBack callBack1){
        callBack = callBack1;
        return this; }...// Go to gitHub to download the complete code
}
Copy the code
MyGreenDaoDbHelper
public class MyGreenDaoDbHelper extends DaoMaster.DevOpenHelper {

    public MyGreenDaoDbHelper(Context context, String name) {
        super(context, name);
    }

    public MyGreenDaoDbHelper(Context context, String name, SQLiteDatabase.CursorFactory factory) {
        super(context, name, factory);
    }

    @Override
    @SuppressWarnings("all")
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        super.onUpgrade(db, oldVersion, newVersion);
        Log.e("MyGreenDaoDbHelper"."--"+oldVersion + "-- Previous and later versions --" + newVersion+"--");
        if (oldVersion < newVersion) {
            Log.e("MyGreenDaoDbHelper"."Perform database upgrade");
            new GreenDaoCompatibleUpdateHelper()
                    .setCallBack(
                            new GreenDaoCompatibleUpdateHelper.GreenDaoCompatibleUpdateCallBack() {
                                @Override
                                public void onFinalSuccess(a) {
                                    Log.e("MyGreenDaoDbHelper"."Database upgrade ===> successful");
                                }

                                @Override
                                public void onFailedLog(String errorMsg) {
                                    Log.e("MyGreenDaoDbHelper"."Upgrade failure log ===>"+errorMsg);
                                }
                            }
                    )
                    .compatibleUpdate(
                            db,
                            PostBeanDao.class,
                            MatterUserBeanDao.class,
                            PropsBeanDao.class,
                            ChannelChatsBeanDao.class,
                            JoinToChannelReqBeanDao.class
                    );
            Log.e("MyGreenDaoDbHelper"."Database upgrade -- done"); }}@Override
    public void onUpgrade(Database db, int oldVersion, int newVersion) {
        // Do not call the parent class, which by default deletes all tables before creating them
        // super.onUpgrade(db, oldVersion, newVersion);}}Copy the code

Possible product-level errors

  • The createTable method cannot be found because the DAO class file was confused
  • The newly added field in the Restore step contains an INT Boolean base type that does not have a default valueSQLiteConstraintException: NOT NULL constraint failedError, workaround, use Integer Boolean type substitution, this you have to compromise, because the authors of greenDao do not care to provide default values when you build tables. You can go to the issue for details

Your concerns

  • If I have too many tables, will the upgrade cause ANR or read/write chaos?
  • Has it been practiced?

1, answer: the source code of sqlLite calls the onUpdrade method entry are added with synchronization keys, so that it will not cause the upgrade can also let you read and write the situation. This is very well designed! Too many watches. Hundreds of them? Then put in the child thread upgrade.

2. Answer: I have used several online apps, which have been running successfully so far.