简体   繁体   English

是否曾调用过onUpgrade方法?

[英]Is the onUpgrade method ever called?

Is the onUpgrade method of SQLiteOpenHelper ever called? 是否曾调用SQLiteOpenHelperonUpgrade方法? If so, when is it called and by what? 如果是这样,什么时候被召唤? If it is not called by the developers, then why is it there? 如果它没有被开发人员调用,那为什么呢? What really happens with that function? 这个功能到底发生了什么? I have seen examples where it drops all the tables, but then a comment says that dropping all the tables is not what you should do. 我已经看到了删除所有表的示例,但随后评论说放弃所有表并不是你应该做的。 Any suggestions? 有什么建议?

For those of you who would like to know the exact moment when onUpgrade() gets called, it is during a call to either getReadableDatabase() or getWriteableDatabase() . 对于那些想知道调用onUpgrade()的确切时刻的人,它是在调用getReadableDatabase()getWriteableDatabase()

To those who are not clear how it ensure it gets triggered, the answer is: It is triggered when the database version provided to the constructor of SqLiteOpenHelper is updated. 对于那些不清楚如何确保它被触发的人,答案是:当提供给SqLiteOpenHelper的构造函数的数据库版本更新时,它会被触发。 Here is a example 这是一个例子

public class dbSchemaHelper extends SQLiteOpenHelper {

private String sql;
private final String D_TAG = "FundExpense";
//update this to get onUpgrade() method of sqliteopenhelper class called
static final int DB_VERSION = 2; 
static final String DB_NAME = "fundExpenseManager";

public dbSchemaHelper(Context context) {
    super(context, DB_NAME, null, DB_VERSION);
    // TODO Auto-generated constructor stub
}

now to...onUpgrade() 现在...... onUpgrade()

@Override
public void onUpgrade(SQLiteDatabase arg0, int arg1, int arg2) {
    sql = "ALTER TABLE " + fundExpenseSchema.Expense.TABLE_NAME + " ADD COLUMN " + fundExpenseSchema.Expense.FUNDID + " INTEGER";
    arg0.execSQL(sql);
}

if your are using the SQLiteOpenHelper the onUpgrade will be called whenever you change the DB version. 如果您正在使用SQLiteOpenHelper,则每当您更改数据库版本时都会调用onUpgrade。 There is an additional requirement for this to work. 还有一个额外的要求。 The db name has to remain the same. 数据库名称必须保持不变。

Old Version:
dbName = "mydb.db"
dbVersion = 1

New Version:
dbName = "mydb.db"
dbVersion = 2

in the onCreate of the content provider you create an instance of the SQLiteOpenHelper that takes these params. 在内容提供程序的onCreate中,您创建了一个采用这些参数的SQLiteOpenHelper实例。 Your SQLiteOpenHelper implementation would look like this: 您的SQLiteOpenHelper实现如下所示:

public static final class MySQLiteOpenHelper extends SQLiteOpenHelper {

        public MySQLiteOpenHelper(Context context, int dbVersion, String dbName) {
            super(context, dbName, null, dbVersion);
        }

        @Override
        public void onCreate(SQLiteDatabase db) {
            //Code to create your db here
        }

        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
            // Code to upgrade your db here
        }

}

It is called when you construct a SQLiteOpenHelper with version newer than the version of the opened database. 当您构造一个版本比打开的数据库版本更新的SQLiteOpenHelper时,会调用它。 What to do depends on the changes in the database that are made between the old and new versions. 做什么取决于旧版本和新版本之间的数据库更改。 The only case when you don't drop a changed table is when the change is noting more than an added column. 如果不删除已更改的表,则唯一的情况是更改的位置超过添加的列。 Then you can use ALTER TABLE statement to add the new column to the table signature. 然后,您可以使用ALTER TABLE语句将新列添加到表签名。

Reviewing all of the posts and running debug code it still was not clear to me when I would see onUpgrade getting called. 回顾所有帖子并运行调试代码,当我看到onUpgrade被调用时,我仍然不清楚它。 I was starting to think that Android had a serious flaw.. 我开始认为Android有一个严重的缺陷..

The info on this page led me to my final resolution. 这个页面上的信息让我得出了最终解决方案。 Thanks a bunch to all contributors! 非常感谢所有贡献者!

This solved it for me... 这为我解决了......

public class DatabaseHelper extends SQLiteOpenHelper {
    public static String TAG = DatabaseHelper.class.getName();
    private static final int DATABASE_VERSION = 42;
    private static final String DATABASE_NAME = "app_database";
    private static final String OLD_TABLE = "old_and_useless";

    public DatabaseHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion ) {
        if( newVersion > oldVersion) {
            Log.d( TAG, "cool! you noticed." );

            db.execSQL( "DROP TABLE IF EXISTS " + OLD_TABLE );
            // other calls like onCreate if necessary

        } else {
            Log.d( TAG, "Hey! didn't you see me?" );
        }

    }

    public void checkDatabaseVersion() {
        SQLiteDatabase db = this.getWritableDatabase();

        // if the DATABASE_VERSION is newer
        //    onUpgrade is called before this is reached
    }


    // other code removed for readability...
}

It's true that getWritableDatabase() and getReadableDatabase() does result in the onUpgrade call. 的确,getWritableDatabase()和getReadableDatabase()确实会导致onUpgrade调用。 I didn't check other methods since these fit the bill for my needs. 我没有检查其他方法,因为这些符合我的需求。

Keep reading, the kicker is coming... 继续阅读,踢球者即将来临......

This code in my initial Activity enlightened me when I finally realized that the db version was updating during my debugging... ugh! 当我终于意识到我的调试期间db版本正在更新时,我的初始Activity中的代码启发了我... 唉!

DatabaseHelper dbHelper = new DatabaseHelper( this );
dbHelper.checkDatabaseVersion();

NOTE: calling the DatabaseHelper constructor updates the db version 注意:调用DatabaseHelper构造函数会更新db版本

After the constructor call, the db was tagged with the new version. 在构造函数调用之后,db被标记为新版本。 Kill the app before a call to getWritableDatabase() or getReadableDatabase() and you're on the new version. 在调用getWritableDatabase()或getReadableDatabase()之前杀死应用程序并且您使用的是新版本。 Thereafter new executions never call the onUpgrade method until DATABASE_VERSION is increased again. 此后,新的执行永远不会调用onUpgrade方法,直到再次增加DATABASE_VERSION。 ( sigh! now it seems ridiculously obvious :) 感叹!现在看起来很荒谬 :)

My suggestion is to add some sort of "checkDatabaseVersion()" to the early stages of your app. 我的建议是在应用程序的早期阶段添加某种“checkDatabaseVersion()”。 Alternately, if you create a SQLiteOpenHelper object make sure you call one of the methods (getWritableDatabase(), getReadableDatabase(), etc.) before your app dies.. 或者,如果您创建一个SQLiteOpenHelper对象,请确保在应用程序死亡之前调用其中一个方法(getWritableDatabase(),getReadableDatabase()等)。

I hope this saves someone else the same head scratching!... :p 我希望这可以节省别人同样的头脑刮伤!...:p

Looking into the SqliteOpenHelper source code, we can know onCreate() , onUpgrade() and onDowngrade get called in getWritableDatabase() or getReadableDatabase() method. 查看SqliteOpenHelper源代码,我们可以知道onCreate()onUpgrade()onDowngradegetWritableDatabase()getReadableDatabase()方法中调用。

public SQLiteDatabase getWritableDatabase() {
    synchronized (this) {
        return getDatabaseLocked(true);
    }
}
public SQLiteDatabase getReadableDatabase() {
    synchronized (this) {
        return getDatabaseLocked(false);
    }
}

private SQLiteDatabase getDatabaseLocked(boolean writable) {
    if (mDatabase != null) {
        if (!mDatabase.isOpen()) {
            // Darn!  The user closed the database by calling mDatabase.close().
            mDatabase = null;
        } else if (!writable || !mDatabase.isReadOnly()) {
            // The database is already open for business.
            return mDatabase;
        }
    }
          . . . . . .  

        final int version = db.getVersion();
        if (version != mNewVersion) {
            if (db.isReadOnly()) {
                throw new SQLiteException("Can't upgrade read-only database from version " +
                        db.getVersion() + " to " + mNewVersion + ": " + mName);
            }

            db.beginTransaction();
            try {
                if (version == 0) {
                    onCreate(db);
                } else {
                    if (version > mNewVersion) {
                        onDowngrade(db, version, mNewVersion);
                    } else {
                        onUpgrade(db, version, mNewVersion);
                    }
                }
                db.setVersion(mNewVersion);
                db.setTransactionSuccessful();
            } finally {
                db.endTransaction();
            }
        }

        onOpen(db);

        if (db.isReadOnly()) {
            Log.w(TAG, "Opened " + mName + " in read-only mode");
        }

        mDatabase = db;
        return db;
    } finally {
        mIsInitializing = false;
        if (db != null && db != mDatabase) {
            db.close();
        }
    }
}

It is actually called when you call getReadableDatabase or getWritableDatabase . 实际上是在调用getReadableDatabasegetWritableDatabase时调用的。

Deep dive: 深潜:

You pass version number in the constructor of SQLiteOpenHelper which is stored in a variable called mNewVersion . 您在SQLiteOpenHelper的构造函数中传递版本号,该构造函数存储在名为mNewVersion的变量中。 That's it. 而已。 Nothing happens at this point. 此时没有任何事情发生。

Everytime you call getReadableDatabase or getWritableDatabase, it will call a method called getDatabaseLocked . 每次调用getReadableDatabase或getWritableDatabase时,它都会调用一个名为getDatabaseLocked的方法。 This method will get the existing version number of the database and compare it with the mNewVersion . 此方法将获取数据库的现有版本号,并将其与mNewVersion进行比较。

  1. If the database with the given name doesn't exist it will call onCreate 如果具有给定名称的数据库不存在,则将调用onCreate
  2. If the new version is greater than old version it will call onUpgrade . 如果新版本大于旧版本,则会调用onUpgrade
  3. If the new version is lower than existing version, an exception will be thrown. 如果新版本低于现有版本,则会引发异常。
  4. If they are equal it will go ahead and open the database. 如果它们相等,它将继续打开数据库。

What should I write in onCreate and onUpgrade ? 我应该在onCreate和onUpgrade上写什么?

onCreate should contain the code that creates a schema for the first time. onCreate应该包含第一次创建模式的代码。

You can leave onUpgrade empty first time since it won't be called the first time. 您可以在第一次将onUpgrade保留为空,因为它不会在第一次调用。 When you want to change the table structure at later stage, that code should go in here. 如果要在以后更改表结构,则应在此处输入该代码。

SQLiteOpenHelper.java (Source code) SQLiteOpenHelper.java (源代码)

public SQLiteDatabase getWritableDatabase() {
    synchronized (this) {
        return getDatabaseLocked(true);
    }
}

 public SQLiteDatabase getReadableDatabase() {
    synchronized (this) {
        return getDatabaseLocked(false);
    }
}

private SQLiteDatabase getDatabaseLocked(boolean writable) {
   .
   .

     final int version = db.getVersion();

        if (version != mNewVersion) {
            if (db.isReadOnly()) {
                throw new SQLiteException("Can't upgrade read-only database from version " +
                        db.getVersion() + " to " + mNewVersion + ": " + mName);
            }

            db.beginTransaction();
            try {
                if (version == 0) {
                    onCreate(db);
                } else {
                    if (version > mNewVersion) {
                        onDowngrade(db, version, mNewVersion);
                    } else {
                        onUpgrade(db, version, mNewVersion);
                    }
                }
                db.setVersion(mNewVersion);
                db.setTransactionSuccessful();
            } finally {
                db.endTransaction();
            }
       }

       onOpen(db);
 }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM