首页 文章

Android:升级数据库版本并添加新表

提问于
浏览
106

我已经为我的应用程序创建了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)";

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);

    }

但由于某种原因,没有创建新表 . 我究竟做错了什么?

5 回答

  • 1

    1. About onCreate() and onUpgrade()

    只要新安装了应用程序,就会调用 onCreate(..) . 只要应用程序升级并启动且数据库版本不同,就会调用 onUpgrade .

    2. Incrementing the db version

    你需要一个像这样的构造函数:

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

    重要提示:单独增加应用程序版本不足以调用 onUpgrade

    3. Don't forget your new users!

    别忘了添加

    database.execSQL(DATABASE_CREATE_color);
    

    您的onCreate()方法或新安装的应用程序将缺少该表 .

    4. How to deal with multiple database changes over time

    如果您有连续的应用程序升级,其中有几个已进行数据库升级,您需要确保检查 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. Keeping your revision numbers under control while developing

    最后......打电话

    adb uninstall <yourpackagename>
    

    完全卸载应用程序 . 当你再次安装时,你可以保证点击 onCreate ,这使你不必在开发时不断将数据库版本增加到平流层......

  • 9

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

    • 当调用 onCreateonUpgrade 方法时

    新安装的应用程序时调用

    • onCreate .
      应用更新时调用

    • onUpgrade .

    • 组织数据库版本我在类方法中管理版本 . 创建接口Migration的实现 . 例如 . 对于第一个版本创建 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.
         }
       }
    
    • 使用迁移类

    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 :已安装应用程序并将其更新为新的应用程序版本时,将调用此方法 . 如果应用程序包含任何数据库更改,则将所有数据库更改放入新的Migration类并增加数据库版本 .

    例如,假设用户已安装具有数据库版本1的应用程序,现在数据库版本更新为2(所有架构更新保留在 MigrationV1ToV2 中) . 现在,当应用程序升级时,我们需要通过在_518886中应用数据库架构更改来升级数据库,如下所示:

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

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

  • 257

    @ 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

  • 1

    您可以使用SQLiteOpenHelper的 onUpgrade 方法 . 在onUpgrade方法中,您将oldVersion作为参数之一 .

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

    最好从 oldVersion 循环到 newVersion ,一次递增 version ,然后逐步升级数据库 . 当数据库版本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;
        }
    
    }
    
  • 2

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

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

相关问题