前面演示两位room数据库的基本使用,今天来看一下数据库的升级/迁移。本文将以新增表和新增列为例来讲解。

这里用到一个数据库调试工具Stetho,大家可以去看看用法:https://github.com/facebook/stetho

1.新加一个数据表

1.1.这样定义未指定主键不能为null,会报错如下:

@Entity(tableName = "device",primaryKeys = {"id"})
public class Device {private String id;private String location;private String deviceName;private String deviceType;...}
错误: You must annotate primary keys with @NonNull. "id" is nullable. SQLite considers this a bug and Room does not allow it. See SQLite docs for details: https://www.sqlite.org/lang_createtable.html
​

所以需要指定主键以及主键不能为null,添加注解@@NonNull

@Entity(tableName = "device",primaryKeys = {"id"})
public class Device {@NonNull //主键不允许为null值private String id;private String location;private String deviceName;private String deviceType;...}

1.2.如果忘记在database的entities中加入我们刚才新建的类,会报如下错误:

错误: There is a problem with the query: [SQLITE_ERROR] SQL error or missing database (no such table: device)
找不到这个表

1.3.如果忘记更新版本号了会报错:

java.lang.IllegalStateException: Room cannot verify the data integrity. Looks like you've changed schema but forgot to update the version number. You can simply fix this by increasing the version number.
译:room无法验证数据库完整性,看起来是你改变了架构但是忘记更新数据库版本了。你只需要增加版本号就可以解决这个问题

1.4.你以为你增加了版本号就解决了

当然,编译时通过了,不过运行的时候就会发现出现了如下问题:

    java.lang.IllegalStateException: A migration from 1 to 2 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.
译:没有找到数据库从版本号1迁移到版本号2的迁移文件。请通过RoomDatabase.Builder.addMigration()方法增加迁移文件,或者RoomDatabase.Builder.fallbackToDestructiveMigration()方法进行处理。

1.5.OK,既然有处理方案,那么先捡简单的来

在创建数database实例的时候,就是通过RoomDatabase.Builder.build()来完成的,我们就在build之前增加这个fallbackToDestructiveMigration()方法试试。先看看系统对fallbackToDestructiveMigration()方法的介绍

/*** Allows Room to destructively recreate database tables if {@link Migration}s that would* migrate old database schemas to the latest schema version are not found.如果找不到旧版本数据库迁移到新版本数据库的迁移文件,并且设置了此方法,那么数据库将会删除重建* <p>* When the database version on the device does not match the latest schema version, Room* runs necessary {@link Migration}s on the database.* <p>* If it cannot find the set of {@link Migration}s that will bring the database to the* current version, it will throw an {@link IllegalStateException}.* <p>* You can call this method to change this behavior to re-create the database instead of* crashing.* <p>一般情况下,当设备数据库版本号与最新架构的版本号不一致时,room将在数据库上运行必要的Migration文件,如果找不到对应的Migration将会抛出异常IllegalStateException,你可以调用此方法来重新创建数据库而不是抛出异常。* If the database was create from an asset or a file then Room will try to use the same* file to re-create the database, otherwise this will delete all of the data in the* database tables managed by Room.如果数据库是使用asset或者file创建的,则room将尝试使用相同的文件创建数据库。否则将删除所有的数据表* <p>* To let Room fallback to destructive migration only during a schema downgrade then use* {@link #fallbackToDestructiveMigrationOnDowngrade()}.** @return This {@link Builder} instance.** @see #fallbackToDestructiveMigrationOnDowngrade()*/@NonNullpublic Builder<T> fallbackToDestructiveMigration() {mRequireMigration = false;mAllowDestructiveMigrationOnDowngrade = true;return this;}

2.利用fallbackToDestructiveMigration()强制升级:

看一下使用了fallbackToDestructiveMigration()方法后的效果,代码:

public static AppDataBase getInstance(Context context) {if (instance == null) {synchronized (AppDataBase.class) {if (instance == null) {instance = Room.databaseBuilder(context.getApplicationContext(),    AppDataBase.class, DATABASE_NAME).fallbackToDestructiveMigration()//数据库更新时删除数据重新创建.build();}}}return instance;}

效果如下,创建成功:

ok,这是最简单的数据库更新,接下来我们来看一下通过Migration来更新数据库。

3.使用Migration升级策略进行升级

3.1.首先,先定义我们版本升级的策略,如我们现在是需要增加一个表device

/*** 版本1-2的迁移策略* 构造方法需传 开始版本号 与 截止版本号*/static final Migration MIGRATION_1_2 = new Migration(1,2) {@Overridepublic void migrate(@NonNull SupportSQLiteDatabase database) {//将数据表device创建出来database.execSQL("CREATE TABLE 'device' ('id'  TEXT NOT NULL,'location' TEXT,'deviceName' TEXT,'deviceType' TEXT,PRIMARY KEY ('id')) ");}};

3.2.然后,在数据库初始化的时候加入版本1-2的迁移策略,这次我们不使用fallbackToDestructiveMigration方法

  
public static AppDataBase getInstance(Context context) {if (instance == null) {synchronized (AppDataBase.class) {if (instance == null) {instance = Room.databaseBuilder(context.getApplicationContext(), AppDataBase.class, DATABASE_NAME)
//                            .fallbackToDestructiveMigration()//数据库更新时删除数据重新创建.addMigrations(MIGRATION_1_2)//指定版本1-2升级时的升级策略.build();}}}return instance;}

3.3.最后看效果:

4.增加数据表的列的数据库升级

4.1.接下来,我们试一下给device表增加一列,不需要默认值,

@Entity(tableName = "device",primaryKeys = {"id"})
public class Device {@NonNull //主键不允许为null值private String id;private String location;private String deviceName;private String deviceType;//新增一列private String deviceCode;...}
​

如果不生成对应的get和set方法,会报错:

错误: Cannot find getter for field.解决这个问题有两种方法

a.不需要在数据表中生成此列,可以直接加上@Ignore注解,(这样操作的不用后续操作了)

b.生成对应的get与set方法(即需要变更数据库,需要继续操作)

注意:记得更新数据库版本号和新增数据库迁移策略,否则将会重现3、4步骤周出现的问题

迁移策略

 /*** 版本2-3的迁移策略* 构造方法需传 开始版本号2 与 截止版本号3*/static final Migration MIGRATION_2_3 = new Migration(2,3) {@Overridepublic void migrate(@NonNull SupportSQLiteDatabase database) {//为device表增加一列database.execSQL("ALTER TABLE device ADD COLUMN deviceCode TEXT ");}};。。。public static AppDataBase getInstance(Context context) {if (instance == null) {synchronized (AppDataBase.class) {if (instance == null) {instance = Room.databaseBuilder(context.getApplicationContext(), AppDataBase.class, DATABASE_NAME)
//                            .fallbackToDestructiveMigration()//数据库更新时删除数据重新创建.addMigrations(MIGRATION_1_2,MIGRATION_2_3)//指定版本升级时的升级策略.build();}}}return instance;}

然后测试如下图,新的列已经添加成功:

注意:版本升级时需要下次操作数据库时才会生效的!!!

4.2.接下来我们再给device表增加一列,并且加默认值:

同样的,在实体类里面增加一个字段—>添加版本迁移策略—>更新database版本号,运行代码

/*** 版本3-4的迁移策略* 构造方法需传 开始版本号3 与 截止版本号4*/static final Migration MIGRATION_3_4 = new Migration(3,4) {@Overridepublic void migrate(@NonNull SupportSQLiteDatabase database) {//为device表增加一列database.execSQL("ALTER TABLE device ADD COLUMN managerType TEXT NOT NULL DEFAULT 'A类' ");}};。。。public static AppDataBase getInstance(Context context) {if (instance == null) {synchronized (AppDataBase.class) {if (instance == null) {instance = Room.databaseBuilder(context.getApplicationContext(), AppDataBase.class, DATABASE_NAME)
//                            .fallbackToDestructiveMigration()//数据库更新时删除数据重新创建.addMigrations(MIGRATION_1_2,MIGRATION_2_3,MIGRATION_3_4)//指定版本升级时的升级策略.build();}}}return instance;}

OK,原有的数据也加上了默认值了

ok,以上内容就是数据库升级/迁移

Android jetpack Room数据库(二)版本升级/迁移相关推荐

  1. Android Jetpack Room数据库全解析

    一.Room简介: Room是Google推出的数据库框架,是一个 ORM (Object Relational Mapping)对象关系映射数据库.其底层还是对SQLite的封装. 使用ORM可以让 ...

  2. 动手为王 | Oracle 数据库跨版本升级迁移实践

    作者简介 李真旭 Oracle ACE 专家,拥有超过10年的 Oracle 运维管理使用经验,参与过众多移动.电信.联通.银行等大型数据库交付项目,具有丰富的运维管理经验,对 Oracle 数据库管 ...

  3. Android Jetpack 之 Room数据库的使用

    Room的小试牛刀 一.前言 二.为什么要使用Room 二.使用步骤 1.添加依赖 2.数据库表Entity的创建 3.数据库Database的创建 4.数据库增删改查操作接口的定义 5.使用Room ...

  4. Android中用文件初始化sqlite 数据库(二)

    博 androidsqlite启动时数据库初始化  方法1已经讲述了一种初始化数据库的方法 它的数据库初始化不是用sql语句,而是用一个现成的sqlite的二进制文件进行直接copy到Android系 ...

  5. Android Jetpack架构组件之 Room(使用、源码篇)

    2019独角兽企业重金招聘Python工程师标准>>> 1.前言 最近简单看了下google推出的框架Jetpack,感觉此框架的内容可以对平时的开发有很大的帮助,也可以解决很多开发 ...

  6. Android Jetpack组件之 Room使用-源码

    1.前言 最近简单看了下google推出的框架Jetpack,感觉此框架的内容可以对平时的开发有很大的帮助,也可以解决很多开发中的问题,对代码的逻辑和UI界面实现深层解耦,打造数据驱动型UI界面. A ...

  7. 携程机票 Android Jetpack 与 Kotlin Coroutines 实践 | 开发者说·DTalk

    本文原作者: 禹昂,携程机票移动端资深工程师,Kotlin 中文社区核心成员,图书<Kotlin 编程实践>译者. 原文发布于: 携程技术 https://mp.weixin.qq.com ...

  8. 干货 | 携程机票 Android Jetpack 与 Kotlin Coroutines 实践

    作者简介 禹昂,携程机票移动端资深工程师,Kotlin 中文社区核心成员,图书<Kotlin 编程实践>译者. 一.前言 1.1 技术背景与选型 自 2017年 Google IO 大会以 ...

  9. Android Jetpack组件之Hilt使用

    前言 最近简单看了下google推出的框架Jetpack,感觉此框架的内容可以对平时的开发有很大的帮助,也可以解决很多开发中的问题,对代码的逻辑和UI界面实现深层解耦,打造数据驱动型UI界面. And ...

最新文章

  1. 谷歌机器智能大牛:AI模型要真正理解人类语言,关键是「序列学习」
  2. Java SE(2)
  3. 通信电子线路期末复习第六章 反馈控制电路
  4. 理清 WebSocket 和 HTTP 的关系
  5. english email writing techniques demo
  6. mysql group_concat distinct,如何在MySQL中使用GROUP_CONCAT和CONCAT与DISTINCT引用单列值?...
  7. 第二阶段_第二小节_C#调试
  8. 事务例子_Redis事务系列之一Redis事务详解
  9. python中的rt_TensorRT学习总结
  10. 2016-02-16
  11. 创建一个Django项目
  12. Nvidia GPU Architecture--Fermi架构笔记
  13. PROFINET IO设备的GSD文件简介
  14. 金蝶EAS,序时簿ListUI只允许选择一行或至少选择一行记录
  15. 小米手机miui12系统连接数据线usb共享网络方法
  16. 传统计算机硬盘和固态硬盘有哪些区别,工业级固态硬盘与传统硬盘有什么区别...
  17. ORACLE EBS/ERP 固定资产总账模块分录
  18. 九龙证券|外资放大招,400亿巨头狂飙!这只翻倍股却突然崩了
  19. 制作一个货币汇率转换器
  20. 对抛物线准线与焦点弦的思考与总结

热门文章

  1. postgresql15.2下载安装详细教程(win10)
  2. primary key 主键
  3. 游戏开发实战之弹球游戏
  4. 给黑莓程序添加快捷键
  5. 啊哈算法之纸牌游戏小猫钓鱼
  6. 安装最好用的计算机软件,8个职场人必装的电脑软件,用过以后就离不开了,太好用!...
  7. 妙用Adobe Audition 系列教程(一):信号发生器
  8. 我的世界神奇宝贝服务器修改神兽刷新率,我的世界神奇宝贝1period;12怎么调神兽刷新率 | 手游网游页游攻略大全...
  9. AI绘画——ChilloutMix模型(现实真人,实现写实逼真的图像)
  10. 用户界面设计黄金三原则