前言:
Room简介:Room持久性库在SQLite的基础上提供了一个抽象层,让用户能够在充分利用SQLite的强大功能的同时,获享更强健的数据库访问机制。
1.添加room依赖:
implementation "androidx.room:room-runtime:2.2.5" annotationProcessor "androidx.room:room-compiler:2.2.5"
2.指定数据库导出路径:
javaCompileOptions { annotationProcessorOptions { arguments = ["room.schemaLocation": "$projectDir/schemas".toString()]//指定数据库schema导出的位置 } }
3.Android提供了一个名为Migration的类,来完成Room的升级。
public Migration(int startVersion, int endVersion)
Migration有两个参数,startVersion和endVersion。startVersion表示当前版本(手机上安装的版本),endVersion表示将要升级到的版本。如果你的手机中的应用程序数据库的版本为1,那么下方Migration会将你的数据库版本从1升级到2。
4.同样,2升级到3的代码如下:
5.如果用户手机上安装的应用程序数据库版本为1,而当前要安装的应用程序数据库版本为3,这种情况该怎么办呢?
这种情况下,Room会先判断当前有没有从1->3的Migration升级方案,如果有,就直接执行从1->3的升级方案,如果没有,那么Room会按照顺序先后执行Migration(1, 2)->Migration(2, 3)以完成升级。
写好Migration之后,我们还需要通过addMigrations()方法,将升级方案添加到Room。
Room.databaseBuilder(context.getApplicationContext(), MyDatabase.class, DATABASE_NAME) .addMigrations(MIGRATION_1_2, MIGRATION_2_3, MIGRATION_1_3) .build();
6.异常处理
假设此时我们升级系统版本为4,却没有为此写相应的Migration,则会出现一个IllegalStateException异常。
Caused by: java.lang.IllegalStateException: A migration from 3 to 4 was required but not found. Please provide the necessary Migration path via RoomDatabase.Builder.addMigration(Migration ...) or allow for destructive migrations via one of the RoomDatabase.Builder.fallbackToDestructiveMigration* methods. at androidx.room.RoomOpenHelper.onUpgrade(RoomOpenHelper.java:117) at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper$OpenHelper.onUpgrade(FrameworkSQLiteOpenHelper.java:124) at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:400) at android.database.sqlite.SQLiteOpenHelper.getReadableDatabase(SQLiteOpenHelper.java:322) at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper$OpenHelper.getReadableSupportDatabase(FrameworkSQLiteOpenHelper.java:103) at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper.getReadableDatabase(Framewor
7.这是因为Room在升级过程中没有匹配到相应的Migration。
为了防止出现升级失败导致应用程序Crash的情况,我们可以在创建数据库时加入fallbackToDestructiveMigration()方法。该方法能够在出现升级异常时,重新创建数据库表。虽然应用程序不会Crash,但由于数据表被重新创建,所有的数据也将会丢失。
Room.databaseBuilder(context.getApplicationContext(), MyDatabase.class, DATABASE_NAME) .fallbackToDestructiveMigration() .addMigrations(MIGRATION_1_2, MIGRATION_2_3, MIGRATION_1_3) .build();
8.在Android中如何修改Room数据库的版本号呢?直接通过@Database标签中的version属性进行修改就可以了。
@Database(entities = {Student.class}, version = 1)
9.Room默认你希望导出Schema文件,如果你不想导出这些文件,那么可以在数据库标签@Database中指定exportSchema = false。但我们建议你导出这些文件,并且,如果你有使用版本控制系统(如Git)来管理代码,可以将这些文件一并提交到仓库。
@Database(entities = {Student.class}, exportSchema = false, version = 1)
10.销毁与重建策略
在Sqlite中修改表结构会比较麻烦。比如我们希望将Student表中的age字段类型从INTEGER改为TEXT。
面对此类需求,最好的方式就是采用“销毁与重建策略”,该策略大致分为以下几个步骤:
10.1 创建一张符合我们要求的临时表temp_Student
10.2 将数据从旧表Student拷贝至临时表temp_Student
10.3 删除旧表Student
10.4 将临时表temp_Student重命名为Student
static final Migration MIGRATION_3_4 = new Migration(3, 4) { @Override public void migrate(SupportSQLiteDatabase database) { database.execSQL("CREATE TABLE temp_Student (" + "id INTEGER PRIMARY KEY NOT NULL," + "name TEXT," + "age TEXT)"); database.execSQL("INSERT INTO temp_Student (id, name, age) " + "SELECT id, name, age FROM Student"); database.execSQL("DROP TABLE Student"); database.execSQL("ALTER TABLE temp_Student RENAME TO Student"); } };