【发布时间】:2017-06-21 15:59:32
【问题描述】:
SQLiteOpenHelper 的 onUpgrade 方法是否被调用过?如果是这样,它是什么时候调用的,由什么调用?如果开发人员没有调用它,那为什么会在那里?该功能到底发生了什么?我已经看到了删除所有表格的示例,但是随后有评论说删除所有表格不是您应该做的。有什么建议么?
【问题讨论】:
标签: java android android-sqlite
SQLiteOpenHelper 的 onUpgrade 方法是否被调用过?如果是这样,它是什么时候调用的,由什么调用?如果开发人员没有调用它,那为什么会在那里?该功能到底发生了什么?我已经看到了删除所有表格的示例,但是随后有评论说删除所有表格不是您应该做的。有什么建议么?
【问题讨论】:
标签: java android android-sqlite
对于那些想知道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);
}
【讨论】:
getReadableDatabase();都打电话给getDatabaseLocked(boolean writable)
如果您使用的是 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
}
}
【讨论】:
onUpgrade 的信息?我需要对此进行官方确认,但我无法在此方法的官方 java 文档中找到它。
当你构造一个版本比打开的数据库版本新的 SQLiteOpenHelper 时调用它。做什么取决于在旧版本和新版本之间对数据库所做的更改。唯一不删除已更改表的情况是,更改不仅仅是添加的列。然后您可以使用 ALTER TABLE 语句将新列添加到表签名中。
【讨论】:
查看所有帖子并运行调试代码,我仍然不清楚何时会看到 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
【讨论】:
查看SqliteOpenHelper源代码,我们可以知道onCreate()、onUpgrade()和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();
}
}
}
【讨论】:
当你调用getReadableDatabase或getWritableDatabase时,它实际调用。
深潜:
您在SQLiteOpenHelper 的构造函数中传递版本号,该版本号存储在名为mNewVersion 的变量中。而已。此时没有任何反应。
每次调用 getReadableDatabase 或 getWritableDatabase 时,都会调用一个名为 getDatabaseLocked 的方法。该方法会获取数据库的现有版本号,并与mNewVersion进行比较。
onCreate
onUpgrade。 我应该在 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);
}
【讨论】: