【Jetpack】使用 Room Migration 升级数据库并导出 Schema 文件 ( Schema ...

打印 上一主题 下一主题

主题 1027|帖子 1027|积分 3081

一、Schema 文件简介



使用 Room Migration 升级数据库 , 需要根据当前数据库版本和目标版本编写一系列 Migration 迁移类 , 并生成一个升级的 Schema 文件 , 该文件是 json 格式的文件 , 此中包含如下内容 :


  • 版本信息 : 包括 当前版本 和 目标版本 ;
  • 创建表语句 : 包括 新增的表的 定义 和 字段信息 ;
  • 删除表语句 : 包括 需要删除的 表的名称 ;
  • 修改表语句 : 包括 需要修改的表的名称 和 需要修改的字段的定义信息 ;
  • 插入数据语句 : 包括 需要插入数据的表的名称 和 插入的数据 ;
  • 删除数据语句 : 包括 需要删除数据的表的名称 和 删除的条件 ;
Schema 文件是 描述 Room 数据库布局的文件 , 通过该文件 , 可以 很方便地开发者了解数据库的汗青变动记录 , 方便排盘问题 ;
Schema 文件 定义了数据库中的表、列、索引等元素的布局 , 并包含了创建和升级数据库的 SQL 脚本 ;

使用 Room 的 Migration 升级数据库 , 生成的 Schema 文件的方式通常是通过 Gradle 构建脚本中的 roomExportSchema 使命,它会将 Schema 文件导出到指定的目次中 , 该目次需要在 build.gradle 构建脚本中配置 ;




二、生成 Schema 文件配置



在进行 Room 数据库升级时 , 可以使用 Room Migration 工具生成 Schema 文件 ;
如果想要 导出 Schema 文件 , 需要在 RoomDatabase 实现类的 @Database 注解中 , 设置 exportSchema = true 参数 ;
  1. @Database(entities = [Student::class], version = 3, exportSchema = true)
  2. abstract class StudentDatabase: RoomDatabase() {
复制代码
在之前的博客中 , exportSchema 参数都设置为了 false , 没有导出 Schema 文件 ;

此外 , 还要在 build.gradle 构建脚本中 配置 Schema 文件的生成位置 , 在 " android / defaultConfig / javaCompileOptions / annotationProcessorOptions " 层级中的 arguments 中 , 配置 "room.schemaLocation": "$projectDir/schemas".toString() 参数 ;
完整的配置层级如下 :
  1. android {
  2.     namespace 'kim.hsl.rvl'
  3.     compileSdk 32
  4.     defaultConfig {
  5.         applicationId "kim.hsl.rvl"
  6.         minSdk 21
  7.         targetSdk 32
  8.         javaCompileOptions {
  9.             annotationProcessorOptions {
  10.                 // 指定 Room Migration 升级数据库导出的 Schema 文件位置
  11.                 arguments = ["room.schemaLocation": "$projectDir/schemas".toString()]
  12.             }
  13.         }
  14.     }
  15. }
复制代码
projectDir 是 Module 模块的根目次 , 生成的 schemas 目次 , 与 src , build , build.gradle 是一个级别的文件 ;




三、生成 Schema 文件过程




1、数据库版本 1 - 首次运行应用


运行数据库版本 1 的应用 , 首次运行 ,
  1.         fun inst(context: Context): StudentDatabase {
  2.             if (!::instance.isInitialized) {
  3.                 synchronized(StudentDatabase::class) {
  4.                     // 创建数据库
  5.                     instance = Room.databaseBuilder(
  6.                         context.applicationContext,
  7.                         StudentDatabase::class.java,
  8.                         "student_database.db")
  9.                         //.addMigrations(MIGRATION_1_2)
  10.                         //.addMigrations(MIGRATION_2_3)
  11.                         //.fallbackToDestructiveMigration()
  12.                         .allowMainThreadQueries() // Room 原则上不允许在主线程操作数据库
  13.                                                   // 如果要在主线程操作数据库需要调用该函数
  14.                         .build()
  15.                 }
  16.             }
  17.             return instance;
  18.         }
复制代码
将 Entity 实体类中 新增的字段 注释掉 ;
  1.     /**
  2.      * 性别字段
  3.      * 数据库表中的列名为 sex
  4.      * 数据库表中的类型为 INTEGER 文本类型
  5.      */
  6.     /*@ColumnInfo(name = "sex", typeAffinity = ColumnInfo.INTEGER)
  7.     var sex: Int = 0*/
  8.     /**
  9.      * degree字段
  10.      * 数据库表中的列名为 sex
  11.      * 数据库表中的类型为 INTEGER 文本类型
  12.      */
  13.     /*@ColumnInfo(name = "degree", typeAffinity = ColumnInfo.INTEGER)
  14.     var degree: Int = 0*/
复制代码
将数据块版本设置为 1 :
  1. @Database(entities = [Student::class], version = 1, exportSchema = true)
  2. abstract class StudentDatabase: RoomDatabase() {
复制代码
首次运行应用 , 生成 数据库版本 1 的 Schema 文件 1.json ;
Schema 文件的生成位置是 " app/schemes/包名/1.json " 路径 ;
  1. {
  2.   "formatVersion": 1,
  3.   "database": {
  4.     "version": 1,
  5.     "identityHash": "acca4b709e6c8b9b88d8328be36b9032",
  6.     "entities": [
  7.       {
  8.         "tableName": "student",
  9.         "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT, `age` INTEGER NOT NULL)",
  10.         "fields": [
  11.           {
  12.             "fieldPath": "id",
  13.             "columnName": "id",
  14.             "affinity": "INTEGER",
  15.             "notNull": true
  16.           },
  17.           {
  18.             "fieldPath": "name",
  19.             "columnName": "name",
  20.             "affinity": "TEXT",
  21.             "notNull": false
  22.           },
  23.           {
  24.             "fieldPath": "age",
  25.             "columnName": "age",
  26.             "affinity": "INTEGER",
  27.             "notNull": true
  28.           }
  29.         ],
  30.         "primaryKey": {
  31.           "columnNames": [
  32.             "id"
  33.           ],
  34.           "autoGenerate": true
  35.         },
  36.         "indices": [],
  37.         "foreignKeys": []
  38.       }
  39.     ],
  40.     "views": [],
  41.     "setupQueries": [
  42.       "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
  43.       "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'acca4b709e6c8b9b88d8328be36b9032')"
  44.     ]
  45.   }
  46. }
复制代码


2、数据库版本 1 升级至 数据库版本 2 - 第二次运行应用


起首 , 设置 Entity 实体类中的字段 , 在 数据库版本 1 的根本上 , 添加 sex 字段 ;
  1.     /**
  2.      * 性别字段
  3.      * 数据库表中的列名为 sex
  4.      * 数据库表中的类型为 INTEGER 文本类型
  5.      */
  6.     @ColumnInfo(name = "sex", typeAffinity = ColumnInfo.INTEGER)
  7.     var sex: Int = 0
复制代码
然后 , 定义 数据库 版本 1 升级为 数据库 版本 2 的 Migration 迁移类 ,
  1.         /**
  2.          * 数据库版本 1 升级到 版本 2 的迁移类实例对象
  3.          */
  4.         val MIGRATION_1_2: Migration = object : Migration(1, 2) {
  5.             override fun migrate(database: SupportSQLiteDatabase) {
  6.                 Log.i("Room_StudentDatabase", "数据库版本 1 升级到 版本 2")
  7.                 database.execSQL("alter table student add column sex integer not null default 1")
  8.             }
  9.         }
复制代码
再后 , 调用 RoomDatabase.Builder#addMigrations 添加上述定义的 Migration 迁移类 ;
  1.         fun inst(context: Context): StudentDatabase {
  2.             if (!::instance.isInitialized) {
  3.                 synchronized(StudentDatabase::class) {
  4.                     // 创建数据库
  5.                     instance = Room.databaseBuilder(
  6.                         context.applicationContext,
  7.                         StudentDatabase::class.java,
  8.                         "student_database.db")
  9.                         .addMigrations(MIGRATION_1_2)
  10.                         //.addMigrations(MIGRATION_2_3)
  11.                         //.fallbackToDestructiveMigration()
  12.                         .allowMainThreadQueries() // Room 原则上不允许在主线程操作数据库
  13.                                                   // 如果要在主线程操作数据库需要调用该函数
  14.                         .build()
  15.                 }
  16.             }
  17.             return instance;
  18.         }
复制代码
末了 , 修改数据库版本 为 2 ,
  1. @Database(entities = [Student::class], version = 2, exportSchema = true)
  2. abstract class StudentDatabase: RoomDatabase() {
复制代码

生成的 数据库 版本 1 升级到 数据库 版本 2 的 Schema 文件如下 :
  1. {
  2.   "formatVersion": 1,
  3.   "database": {
  4.     "version": 2,
  5.     "identityHash": "84fb235f8062b0a6b0c8d1a6d1035c4f",
  6.     "entities": [
  7.       {
  8.         "tableName": "student",
  9.         "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT, `age` INTEGER NOT NULL, `sex` INTEGER NOT NULL)",
  10.         "fields": [
  11.           {
  12.             "fieldPath": "id",
  13.             "columnName": "id",
  14.             "affinity": "INTEGER",
  15.             "notNull": true
  16.           },
  17.           {
  18.             "fieldPath": "name",
  19.             "columnName": "name",
  20.             "affinity": "TEXT",
  21.             "notNull": false
  22.           },
  23.           {
  24.             "fieldPath": "age",
  25.             "columnName": "age",
  26.             "affinity": "INTEGER",
  27.             "notNull": true
  28.           },
  29.           {
  30.             "fieldPath": "sex",
  31.             "columnName": "sex",
  32.             "affinity": "INTEGER",
  33.             "notNull": true
  34.           }
  35.         ],
  36.         "primaryKey": {
  37.           "columnNames": [
  38.             "id"
  39.           ],
  40.           "autoGenerate": true
  41.         },
  42.         "indices": [],
  43.         "foreignKeys": []
  44.       }
  45.     ],
  46.     "views": [],
  47.     "setupQueries": [
  48.       "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
  49.       "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '84fb235f8062b0a6b0c8d1a6d1035c4f')"
  50.     ]
  51.   }
  52. }
复制代码


3、数据库版本 2 升级至 数据库版本 3 - 第三次运行应用


起首 , 设置 Entity 实体类中的字段 , 在 数据库版本 2 的根本上 , 添加 degree 字段 ;
  1.     /**
  2.      * 性别字段
  3.      * 数据库表中的列名为 sex
  4.      * 数据库表中的类型为 INTEGER 文本类型
  5.      */
  6.     @ColumnInfo(name = "sex", typeAffinity = ColumnInfo.INTEGER)
  7.     var sex: Int = 0
  8.     /**     * degree字段     * 数据库表中的列名为 sex     * 数据库表中的类型为 INTEGER 文本类型     */    @ColumnInfo(name = "degree", typeAffinity = ColumnInfo.INTEGER)    var degree: Int = 0
复制代码
然后 , 定义 数据库 版本 2 升级为 数据库 版本 3 的 Migration 迁移类 ,
  1.         /**
  2.          * 数据库版本 2 升级到 版本 3 的迁移类实例对象
  3.          */
  4.         val MIGRATION_2_3: Migration = object : Migration(2, 3) {
  5.             override fun migrate(database: SupportSQLiteDatabase) {
  6.                 Log.i("Room_StudentDatabase", "数据库版本 2 升级到 版本 3")
  7.                 database.execSQL("alter table student add column degree integer not null default 1")
  8.             }
  9.         }
复制代码
再后 , 调用 RoomDatabase.Builder#addMigrations 添加上述定义的 Migration 迁移类 ;
  1.         fun inst(context: Context): StudentDatabase {
  2.             if (!::instance.isInitialized) {
  3.                 synchronized(StudentDatabase::class) {
  4.                     // 创建数据库
  5.                     instance = Room.databaseBuilder(
  6.                         context.applicationContext,
  7.                         StudentDatabase::class.java,
  8.                         "student_database.db")
  9.                         .addMigrations(MIGRATION_1_2)
  10.                         .addMigrations(MIGRATION_2_3)
  11.                         //.fallbackToDestructiveMigration()
  12.                         .allowMainThreadQueries() // Room 原则上不允许在主线程操作数据库
  13.                                                   // 如果要在主线程操作数据库需要调用该函数
  14.                         .build()
  15.                 }
  16.             }
  17.             return instance;
  18.         }
复制代码
末了 , 修改数据库版本 为 3 ,
  1. @Database(entities = [Student::class], version = 2, exportSchema = true)
  2. abstract class StudentDatabase: RoomDatabase() {
复制代码

生成的 数据库 版本 2 升级到 数据库 版本 3 的 Schema 文件如下 :
  1. {
  2.   "formatVersion": 1,
  3.   "database": {
  4.     "version": 3,
  5.     "identityHash": "d88859680a038f5155613d94de7888cc",
  6.     "entities": [
  7.       {
  8.         "tableName": "student",
  9.         "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT, `age` INTEGER NOT NULL, `sex` INTEGER NOT NULL, `degree` INTEGER NOT NULL)",
  10.         "fields": [
  11.           {
  12.             "fieldPath": "id",
  13.             "columnName": "id",
  14.             "affinity": "INTEGER",
  15.             "notNull": true
  16.           },
  17.           {
  18.             "fieldPath": "name",
  19.             "columnName": "name",
  20.             "affinity": "TEXT",
  21.             "notNull": false
  22.           },
  23.           {
  24.             "fieldPath": "age",
  25.             "columnName": "age",
  26.             "affinity": "INTEGER",
  27.             "notNull": true
  28.           },
  29.           {
  30.             "fieldPath": "sex",
  31.             "columnName": "sex",
  32.             "affinity": "INTEGER",
  33.             "notNull": true
  34.           },
  35.           {
  36.             "fieldPath": "degree",
  37.             "columnName": "degree",
  38.             "affinity": "INTEGER",
  39.             "notNull": true
  40.           }
  41.         ],
  42.         "primaryKey": {
  43.           "columnNames": [
  44.             "id"
  45.           ],
  46.           "autoGenerate": true
  47.         },
  48.         "indices": [],
  49.         "foreignKeys": []
  50.       }
  51.     ],
  52.     "views": [],
  53.     "setupQueries": [
  54.       "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
  55.       "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'd88859680a038f5155613d94de7888cc')"
  56.     ]
  57.   }
  58. }
复制代码


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

南飓风

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表