35

是否曾经调用过的onUpgrade方法SQLiteOpenHelper?如果是这样,它是什么时候调用的,由什么调用?如果开发人员没有调用它,那为什么会在那里?该功能到底发生了什么?我已经看到了删除所有表格的示例,但是随后有评论说删除所有表格不是您应该做的。有什么建议么?

4

6 回答 6

37

对于那些想知道onUpgrade()被呼叫的确切时间的人,这是在呼叫getReadableDatabase()或的过程中getWriteableDatabase()

对于那些不清楚它如何确保触发的人,答案是:它在提供给构造函数的数据库版本SqLiteOpenHelper更新时触发。这是一个例子

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
}

现在到... 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);
}
于 2011-12-24T00:16:30.680 回答
29

如果您使用的是 SQLiteOpenHelper,则无论何时更改数据库版本都会调用 onUpgrade。有一个额外的要求才能工作。数据库名称必须保持不变。

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

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

在内容提供者的 onCreate 中,您创建一个接受这些参数的 SQLiteOpenHelper 实例。您的 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
        }

}
于 2011-04-12T20:29:28.877 回答
22

当你构造一个版本比打开的数据库版本新的 SQLiteOpenHelper 时,它会被调用。做什么取决于在旧版本和新版本之间对数据库所做的更改。唯一不删除已更改表的情况是,更改不仅仅是添加的列。然后您可以使用 ALTER TABLE 语句将新列添加到表签名中。

于 2010-07-02T07:17:41.140 回答
5

查看所有帖子并运行调试代码,我仍然不清楚何时会看到 onUpgrade 被调用。我开始认为Android有一个严重的缺陷..

此页面上的信息使我做出了最终决定。非常感谢所有贡献者!

这为我解决了它...

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...
}

确实 getWritableDatabase() 和 getReadableDatabase() 确实会导致 onUpgrade 调用。我没有检查其他方法,因为这些方法符合我的需要。

继续阅读,踢球者来了……

当我终于意识到在我的调试过程中数据库版本正在更新时,我最初的 Activity 中的这段代码启发了我…… 呃!

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

注意:调用 DatabaseHelper 构造函数会更新数据库版本

在构造函数调用之后,数据库被标记为新版本。在调用 getWritableDatabase() 或 getReadableDatabase() 之前终止应用程序,您将使用新版本。此后,新的执行永远不会调用 onUpgrade 方法,直到 DATABASE_VERSION 再次增加。(叹气!现在看起来很明显 :)

我的建议是在应用的早期阶段添加某种“checkDatabaseVersion()”。或者,如果您创建 SQLiteOpenHelper 对象,请确保在应用程序终止之前调用其中一种方法(getWritableDatabase()、getReadableDatabase() 等)。

我希望这可以避免其他人同样头疼!...:p

于 2015-05-30T06:12:11.050 回答
3

查看SqliteOpenHelper源代码,我们可以知道onCreate(),onUpgrade()并在or方法onDowngrade中被调用。getWritableDatabase()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();
        }
    }
}
于 2015-10-20T04:24:33.103 回答
2

实际上是在您调用getReadableDatabaseor时调用getWritableDatabase的。

深潜:

您在构造函数中传递版本号,该版本号SQLiteOpenHelper存储在一个名为mNewVersion. 就是这样。此时没有任何反应。

每次调用 getReadableDatabase 或 getWritableDatabase 时,都会调用一个名为getDatabaseLocked. 此方法将获取数据库的现有版本号并将其与mNewVersion.

  1. 如果具有给定名称的数据库不存在,它将调用onCreate
  2. 如果新版本大于旧版本,它将调用onUpgrade.
  3. 如果新版本低于现有版本,则会抛出异常。
  4. 如果它们相等,它将继续并打开数据库。

我应该在 onCreate 和 onUpgrade 中写什么?

onCreate应该包含第一次创建模式的代码。

您可以onUpgrade第一次留空,因为第一次不会调用它。当您想在稍后阶段更改表结构时,该代码应该放在此处。

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);
 }
于 2017-06-21T07:59:32.530 回答