Android: 升级 DB 版本并添加新表

我已经为我的应用程序创建了 sqlite 表,但是现在我想向数据库添加一个新表。

我改变了数据库的版本如下

private static final int DATABASE_VERSION = 2;

并添加字符串以创建表

private static final String DATABASE_CREATE_color =
"CREATE TABLE IF NOT EXISTS files(color text, incident_id text)";

onCreateonUpgrade如下:

@Override
public void onCreate(SQLiteDatabase database) {
database.execSQL(DATABASE_CREATE_incident);
database.execSQL(DATABASE_CREATE_audio);
database.execSQL(DATABASE_CREATE_video);
database.execSQL(DATABASE_CREATE_image);


}


@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
//drop table and add new tables when version 2 released.
db.execSQL(DATABASE_CREATE_color);


}

但是由于某种原因,新表没有被创建。我做错了什么?

108301 次浏览

关于 onCreate ()和 onUpgrade ()

每当新安装应用程序时,就调用 onCreate(..)。只要应用程序升级和启动,而 数据库版本不一样,就会调用 onUpgrade

2. Incrementing the db version

你需要这样的构造函数:

MyOpenHelper(Context context) {
super(context, "dbname", null, 2); // 2 is the database version
}

重要: 仅仅增加应用程序版本是不够的 onUpgrade被调用!

3. 不要忘记你的新用户!

别忘了加上

database.execSQL(DATABASE_CREATE_color);

你的 onCreate ()方法,或者新安装的应用程序将缺少表。

4. 如何处理多个数据库随时间的变化

当你有连续的应用程序升级,其中一些有数据库升级,你要确保检查 oldVersion:

onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
switch(oldVersion) {
case 1:
db.execSQL(DATABASE_CREATE_color);
// we want both updates, so no break statement here...
case 2:
db.execSQL(DATABASE_CREATE_someothertable);
}
}

This way when a user upgrades from version 1 to version 3, they get both updates. When a user upgrades from version 2 to 3, they just get the revision 3 update... After all, you can't count on 100% of your user base to upgrade each time you release an update. Sometimes they skip an update or 12 :)

5. 在开发过程中控制修订数量

终于... 打电话来了

adb uninstall <yourpackagename>

完全卸载应用程序。当你再次安装时,你保证会达到 onCreate,这使你不必不断增加数据库版本到平流层,因为你开发..。

你的代码看起来没错。我的建议是数据库已经认为它已经升级了。如果在增加版本号之后执行项目,但在添加 execSQL调用之前,测试设备/模拟器上的数据库可能已经认为它处于版本2。

验证这一点的一个快速方法是将版本号更改为3——如果在此之后进行了升级,那么您知道这只是因为您的设备认为它已经进行了升级。

您可以使用 SQLiteOpenHelper 的 onUpgrade方法。

onUpgrade中使用 switch,在每个 case中使用版本号来跟踪当前版本的数据库。

最好是从 oldVersion循环到 newVersion,每次递增 version1,然后逐步升级数据库。这是非常有帮助的人与数据库版本1升级后,应用程序很长一段时间,以一个版本使用数据库版本7和应用程序开始崩溃,因为某些不兼容的变化。

然后,数据库中的更新将分步进行,覆盖所有可能的情况,例如,为每个新版本合并数据库中的更改,从而防止应用程序崩溃。

例如:

public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
switch (oldVersion) {
case 1:
String sql = "ALTER TABLE " + TABLE_SECRET + " ADD COLUMN " + "name_of_column_to_be_added" + " INTEGER";
db.execSQL(sql);
break;


case 2:
String sql = "SOME_QUERY";
db.execSQL(sql);
break;
}


}

@ jkschneider 的回答是正确的,但是有一个更好的方法。

为每个更新在 sql 文件中写入所需的更改,如链接 https://riggaroo.co.za/android-sqlite-database-use-onupgrade-correctly/中所述

From _ 1 _ to _ 2. sql

ALTER TABLE books ADD COLUMN book_rating INTEGER;

From _ 2 _ to _ 3. sql

ALTER TABLE books RENAME TO book_information;

From _ 3 _ to _ 4. sql

ALTER TABLE book_information ADD COLUMN calculated_pages_times_rating INTEGER;
UPDATE book_information SET calculated_pages_times_rating = (book_pages * book_rating) ;

这些. sql 文件将根据数据库的版本在 onUpgrade ()方法中执行。

DatabaseHelper.java

public class DatabaseHelper extends SQLiteOpenHelper {


private static final int DATABASE_VERSION = 4;


private static final String DATABASE_NAME = "database.db";
private static final String TAG = DatabaseHelper.class.getName();


private static DatabaseHelper mInstance = null;
private final Context context;


private DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
this.context = context;
}


public static synchronized DatabaseHelper getInstance(Context ctx) {
if (mInstance == null) {
mInstance = new DatabaseHelper(ctx.getApplicationContext());
}
return mInstance;
}


@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(BookEntry.SQL_CREATE_BOOK_ENTRY_TABLE);
// The rest of your create scripts go here.


}




@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.e(TAG, "Updating table from " + oldVersion + " to " + newVersion);
// You will not need to modify this unless you need to do some android specific things.
// When upgrading the database, all you need to do is add a file to the assets folder and name it:
// from_1_to_2.sql with the version that you are upgrading to as the last version.
try {
for (int i = oldVersion; i < newVersion; ++i) {
String migrationName = String.format("from_%d_to_%d.sql", i, (i + 1));
Log.d(TAG, "Looking for migration file: " + migrationName);
readAndExecuteSQLScript(db, context, migrationName);
}
} catch (Exception exception) {
Log.e(TAG, "Exception running upgrade script:", exception);
}


}


@Override
public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {


}


private void readAndExecuteSQLScript(SQLiteDatabase db, Context ctx, String fileName) {
if (TextUtils.isEmpty(fileName)) {
Log.d(TAG, "SQL script file name is empty");
return;
}


Log.d(TAG, "Script found. Executing...");
AssetManager assetManager = ctx.getAssets();
BufferedReader reader = null;


try {
InputStream is = assetManager.open(fileName);
InputStreamReader isr = new InputStreamReader(is);
reader = new BufferedReader(isr);
executeSQLScript(db, reader);
} catch (IOException e) {
Log.e(TAG, "IOException:", e);
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
Log.e(TAG, "IOException:", e);
}
}
}


}


private void executeSQLScript(SQLiteDatabase db, BufferedReader reader) throws IOException {
String line;
StringBuilder statement = new StringBuilder();
while ((line = reader.readLine()) != null) {
statement.append(line);
statement.append("\n");
if (line.endsWith(";")) {
db.execSQL(statement.toString());
statement = new StringBuilder();
}
}
}
}

An example project is provided in the same link also : https://github.com/riggaroo/AndroidDatabaseUpgrades

处理数据库版本是应用程序开发的重要组成部分。我假设您已经有了扩展 SQLiteOpenHelper的 AppDbHelper 类。当您扩展它时,您将需要实现 onCreateonUpgrade方法。

  1. onCreateonUpgrade方法调用

    • 在新安装应用程序时调用 onCreate
    • 应用程序更新时调用 onUpgrade
  2. 组织数据库版本 我管理类方法中的版本。创建接口迁移的实现。例如,对于第一个版本创建 MigrationV1类,第二个版本创建 MigrationV1ToV2(这是我的变数命名原则)


public interface Migration {
void run(SQLiteDatabase db);//create tables, alter tables
}

迁移示例:

public class MigrationV1ToV2 implements Migration{
public void run(SQLiteDatabase db){
//create new tables
//alter existing tables(add column, add/remove constraint)
//etc.
}
}
  1. 使用迁移类

onCreate: 由于 onCreate将在应用程序新安装时调用,因此我们还需要执行所有迁移(数据库版本更新)。onCreate看起来是这样的:

public void onCreate(SQLiteDatabase db){
Migration mV1=new MigrationV1();
//put your first database schema in this class
mV1.run(db);
Migration mV1ToV2=new MigrationV1ToV2();
mV1ToV2.run(db);
//other migration if any
}

onUpgrade: 当应用程序已经安装并更新到新的应用程序版本时,将调用此方法。如果应用程序包含任何数据库更改,则将所有数据库更改放入新的迁移类并增加数据库版本。

For example, lets say user has installed application which has database version 1, and now database version is updated to 2(all schema updates kept in MigrationV1ToV2). Now when application upgraded, we need to upgrade database by applying database schema changes in MigrationV1ToV2 like this:

public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if (oldVersion < 2) {
//means old version is 1
Migration migration = new MigrationV1ToV2();
migration.run(db);
}
if (oldVersion < 3) {
//means old version is 2
}
}

注意: 对数据库模式的所有升级(在 onUpgrade中提到)都应该在 onCreate中执行

in first db version ,table is as below:

   String createUserTable = "CREATE TABLE IF NOT EXISTS "+ user + " (" +
USER_ID + " INTEGER PRIMARY KEY, " +
USER_NAME + " TEXT NOT NULL, " +
USER_FAMILY + " TEXT NOT NULL, " +
USER_LIVING_STATUS + " INTEGER DEFAULT 0);";

在第二个版本的数据库中,我们添加了一个新的列的名称的颜色,这就是为什么 upgrade codes should be like below.

@Override
public void onUpgrade(SQLiteDatabase mydb, int oldVersion, int newVersion) {
   

if (newVersion > oldVersion) {
     

/******************************** delete the last table and create new table with new columns  and copy    the former to new one *********************************/
       

// here we added color column to new table
mydb.execSQL("CREATE TABLE IF NOT EXISTS user_tmp ("
+ "user_id integer, user_name text, user_family text, user_color text,user_living_status integer);");
mydb.execSQL("INSERT INTO user_tmp(user_id,user_name,user_family,user_living_status) SELECT * FROM user");
mydb.execSQL("drop table user;");
mydb.execSQL("ALTER TABLE user_tmp RENAME TO user");
       

}
}