Android: обновление версии БД и добавление новой таблицы
Я уже создал таблицы sqlite для своего приложения, но теперь я хочу добавить новую таблицу в базу данных.
Я изменил версию DB, как показано ниже
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)";
onCreate
и onUpgrade
как показано ниже:
@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);
}
но по какой-то причине новая таблица не создается. Что я делаю не так?
5 ответов
1. О onCreate () и onUpgrade ()
onCreate(..)
вызывается, когда приложение свежеустановленная. onUpgrade
вызывается всякий раз, когда приложение обновляется и запускается и версия базы данных - это не то же самое.
2. Увеличение версии БД
конструктор как:
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);
}
}
таким образом, когда обновления пользователей с версии 1 до версии 3, они получают оба обновления. Когда пользователь обновляется с версии 2 до 3, они просто получают обновление версии 3... В конце концов, вы не можете рассчитывать на 100% вашей пользовательской базы для обновления каждый раз, когда вы выпускаете обновление. Иногда они пропускают обновление или 12:)
5. Сохранение номеров версий под контролем при разработке
и наконец... зову
adb uninstall <yourpackagename>
полностью удаляет приложение. Когда вы установите снова, вы гарантированно нажмете onCreate
что удерживает вас от необходимости продолжать увеличивать версию базы данных в стратосферу по мере развития...
ваш код выглядит правильно. Мое предложение заключается в том, что база данных уже думает, что она обновлена. Если вы выполнили проект после увеличения номера версии, но перед добавлением execSQL
вызов, база данных на вашем тестовом устройстве / эмуляторе может уже поверить, что она находится в версии 2.
быстрый способ проверить это-изменить номер версии на 3 -- если он обновится после этого, вы знаете, что это было только потому, что ваше устройство считало, что оно уже обновлено.
можно использовать
на onUpgrade
использовать switch
и в каждом из case
s используйте номер версии для отслеживания текущей версии базы данных.
лучше всего, что вы петля от oldVersion
to newVersion
, incrementing version
по 1 за раз, а затем обновить базы данных шаг за шагом. Это очень полезно, когда кто-то с базой данных версии 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();
}
}
}
}
пример проекта приведен в той же ссылке:https://github.com/riggaroo/AndroidDatabaseUpgrades
работа с версиями базы данных является очень важной частью разработки приложений. Я предполагаю, что у вас уже есть расширение класса AppDbHelper SQLiteOpenHelper
. Когда вы расширяете его, вам нужно будет реализовать onCreate
и onUpgrade
метод.
-
, когда
onCreate
иonUpgrade
методы, называемые-
onCreate
вызывается при новой установке приложения. -
onUpgrade
вызывается при обновлении приложения.
-
организация Версия базы данных Я управляю версиями в методах класса. Создание реализации миграции интерфейса. Например. Для первой версии create
MigrationV1
класс, вторая версия createMigrationV1ToV2
(это мое соглашение об именах)
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.
}
}
- использование классов миграции
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
: этот метод будет вызываться, когда приложение уже установлено и обновлено до новой версии приложения. Если приложение содержит какие-либо изменения базы данных, поместите все изменения базы данных в новый класс миграции и увеличьте версию базы данных.
например, допустим, пользователь установил приложение с базой данных версии 1, и теперь версия базы данных обновляется до 2(все обновления схемы держали в MigrationV1ToV2
). Теперь, когда приложение обновлено, нам нужно обновить базу данных, применив изменения схемы базы данных в MigrationV1ToV2
такой:
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