Android room数据库注解、迁移

注解

@Entity:使用Room定义一个数据实体User(带Entity注解的类),一个Entity表由主键和一个或多个列组成,User中的每个实例都代表着User表中的一行,tableName后面为表名,在不指定表名的情况下,默认将类名作为数据表的名称。
@ColumnInfo:Room默认使用字段名称作为列名称,如需更改,采用@ColumnInfo注解设置name属性(列名)。

java 复制代码
 @ColumnInfo(name = "user_name",typeAffinity = ColumnInfo.TEXT,defaultValue = "默认值")

@Ignore:表示会忽略这个字段,不进行记录
@PrimaryKey :每一个实体类都需要一个唯一的标识即主键。
@NonNull:该字段不可为空
@Embedded :实体类中引用其它实体类

Room 不允许对象引用,通过@TypeConverter自定义类型转换器
@Embedded------引用其它实体类:假如实体类中包含了多个同一类型的嵌入字段(比如一个人User拥有两本Book),我们可以通过设置prefix属性来保持每列的唯一性。Room会将提供的值添加到嵌入对象的每个列名的开头。

java 复制代码
//@Embedded(prefix = "one"),这个是区分唯一性的,
//比如说一这个人有2本书并添加了tag,那么在数据表中就会以prefix+属性值命名
@Embedded(prefix = "one")
private Book address;
@Embedded(prefix = "two")
private Book address;

@Dao: 使用@Dao注解定义为一个BaseDao接口,增加基本的插入、删除、修改方法,再定义一个UserDao去扩展BaseDao接口,增加需要的方法。
@Insert:插入,可以定义将其参数插入数据库中的相应表的方法

java 复制代码
OnConflictStrategy.REPLACE:冲突策略是取代旧数据同时继续事务
OnConflictStrategy.ROLLBACK:冲突策略是回滚事务
OnConflictStrategy.ABORT:冲突策略是终止事务
OnConflictStrategy.FAIL:冲突策略是事务失败
OnConflictStrategy.IGNORE:冲突策略是忽略冲突
最新代码中ROLLBACK 和 FAIL 已经deprecated了,使用ABORT替代

@Delete:删除,可以定义用于从数据库表中删除特定行的方法
@Update:修改,可以定义用于更新数据库表中特定行的方法
@Query: 查询,可以从应用的数据库查询指定数据,用于更加复杂的插入、删除、更新操作

@DataBase:定义用户保存数据库的MyDataBase类,定义数据库配置。
@exportSchema:是否导出数据库表,默认true

如果不指定,需要将exportSchema = false,或者在app的build.gradle里设置对应的路径,否则会出现如下报错

java 复制代码
Schema export directory is not provided to the annotation processor so we cannot export the schema. You can either provide `room.schemaLocation` annotation processor argument OR set exportSchema to false.
java 复制代码
        //指定room.schemaLocation生成的文件路径, java环境(两者选一,看项目环境)
    defaultConfig {
        javaCompileOptions {
            annotationProcessorOptions {
                arguments = ["room.schemaLocation": "$projectDir/schemas".toString()]
            }
        }


        //指定room.schemaLocation生成的文件路径, kotlin环境 (两者选一,看项目环境)
        kapt {
            arguments {
                arg("room.schemaLocation", "$projectDir/schemas")
            }
        }
   }

@Database(entities = {User.class, Book.class}, version = 2,exportSchema = false)

@DeleteTable:删除数据表
DROP TABLE user_table
@RenameTable: 重命名数据表
database.execSQL("RENAME TABLE user_table to new_table_name");
@DeleteColumn:删除数据表中的列
database.execSQL("ALTER TABLE user_table ADD COLUMN job TEXT");
@RenameColumn:重命名数据表中的列
database.execSQL("ALTER TABLE user_table RENAME COLUMN job TO user_job");

迁移

在 Room 中使用 Migration 迁移工具 升级数据库步骤 :

如果不想提供迁移策略,直接进行破坏性升级(不保留之前的数据),可以直接使用 fallbackToDestructiveMigration()

  • 更新数据模型 :
    如果要 更改数据库的结构 , 更新 Entity 实体类 , 修改实体类就是修改数据库表结构 ; 修改 Dao 数据库访问接口对象 , 包括添加 / 删除 / 修改 表 / 列 / 索引 ;
  • 创建迁移类 :
    创建一个用于执行数据库迁移的 迁移类 Migration , Migration 迁移类应 实现 Room 的 Migration 接口 , 并 定义数据库从旧版本迁移到新版本的操作 ;
  • 指定迁移规则 :
    在 Room 数据库的构建器中 , 使用 addMigrations 方法指定迁移规则 , 该方法接受一组 Migration 迁移对象 , 每个 Migration 迁移对象 代表一个数据库版本之间的迁移操作 ;
  • 执行迁移 :
    当应用程序启动并访问数据库时,Room 将自动检测数据库版本并执行适当的迁移操作 , 应用程序可以无缝地将旧版本的数据库迁移到新版本,而不会丢失现有的数据。
自动升级

exportSchema必须设置为true(默认为true),否则会出现如下报错
Cannot create auto migrations when export schema is OFF.

首先需要在@Database注解中增加autoMigrations

java 复制代码
@Database(entities = {User.class, Book.class}, version = 3,exportSchema = true,autoMigrations = @AutoMigration(from = 2,to = 3,spec = UserRoomDatabase.TestAutoMigration.class))

如果 Room 发现迁移过程中有歧义,并且在未提供更多信息的时候无法制定确切的自迁移方案,在编译期间就会发生错误,这时开发者需要提供一个 AutoMigrationSpec 的实现。多数情况下,自迁移发生错误都是由下列的原因造成的。

  • 删除或者重命名数据表名
  • 删除或者重命名数据表的列名
java 复制代码
    @RenameColumn(tableName = "user_table", fromColumnName = "job", toColumnName = "user_job")
    static class TestAutoMigration implements AutoMigrationSpec { }
手动升级

//修改version = 2
@Database(entities = {User.class, Book.class}, version = 2,exportSchema = true)

创建具体的版本迁移策略

java 复制代码
    //添加字段 具体的版本迁移策略
    public static final Migration MIGRATION_1_2 = new Migration(1, 2) {
        @Override
        public void migrate(@NonNull SupportSQLiteDatabase database) {
            //添加字段
//            database.execSQL("ALTER TABLE user_table ADD COLUMN job TEXT NOT NULL DEFAULT '民工'");
            database.execSQL("ALTER TABLE user_table ADD COLUMN job TEXT");
//            database.execSQL("ALTER TABLE user_table RENAME COLUMN job TO user_job");
        }
    };



    //单例创建database
    static UserRoomDatabase getDatabase(final Context context) {
        if (INSTANCE == null) {
            synchronized (UserRoomDatabase.class) {
                if (INSTANCE == null) {
                    INSTANCE = Room.databaseBuilder(
                            context.getApplicationContext(),
                            UserRoomDatabase.class, DATABASE_NAME)
                            .addMigrations(MIGRATION_1_2)////添加完了migration后,根据Room.builder把我们版本更新的信息add进去
                            .build();
                }
            }
        }
        return INSTANCE;
    }

补充

exportSchema设置为 true后,会在指定路径(app的build.gradle里设置的)下生成一个json文件,里面有不同版本的表的信息。

👀关注公众号:Android老皮!!!欢迎大家来找我探讨交流👀

相关推荐
隔壁老王1569 分钟前
mysql实时同步到es
数据库·mysql·elasticsearch
openinstall全渠道统计22 分钟前
免填邀请码工具:赋能六大核心场景,重构App增长新模型
android·ios·harmonyos
想要打 Acm 的小周同学呀32 分钟前
Redis三剑客解决方案
数据库·redis·缓存
rkmhr_sef33 分钟前
Redis 下载与安装 教程 windows版
数据库·windows·redis
双鱼大猫44 分钟前
一句话说透Android里面的ServiceManager的注册服务
android
双鱼大猫1 小时前
一句话说透Android里面的SystemServer进程的作用
android
双鱼大猫1 小时前
一句话说透Android里面的View的绘制流程和实现原理
android
双鱼大猫2 小时前
一句话说透Android里面的Window的内部机制
android
双鱼大猫2 小时前
一句话说透Android里面的为什么要设计Window?
android
双鱼大猫2 小时前
一句话说透Android里面的主线程创建时机,frameworks层面分析
android