【Jetpack】Room 中的销毁重建策略 ( 创建临时数据库表 | 拷贝数据库表数据 | 删除旧表 | 临时数据库表重命名 )

    <link rel="stylesheet" href="https://csdnimg.cn/release/blogv2/dist/mdeditor/css/editerView/kdoc_html_views-1a98987dfd.css">
    <link rel="stylesheet" href="https://csdnimg.cn/release/blogv2/dist/mdeditor/css/editerView/ck_htmledit_views-25cebea3f9.css">
            <div id="content_views" class="markdown_views prism-tomorrow-night-eighties">
                <svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
                    <path stroke-linecap="round" d="M5,0 0,2.5 5,5z" id="raphael-marker-block" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></path>
                </svg>
                <p></p> 





一、销毁 和 重建策略



在 Android 中使用 Room 操作 SQLite 数据库 , 如果 SQLite 数据库表 修改比较繁琐 ,

如 : 涉及到 修改 数据库表字段的数据类型 , 需要逐个修改数据库值 ;

该环境下 使用 销毁 和 重建策略 是 最佳的方案 ;


销毁 和 重建策略 执行步骤 : 以 Table 表为例 , 要对 Table 表中的数据进行繁琐的操作 ;

  • 首先 , 创建一张 符合 新数据库表结构 的 临时数据库表 Temp_Table 表 ;
  • 然后 , 将 旧数据库表 Table 表中的数据 拷贝到 临时数据库表 Temp_Table 表中 , 如果需要修改 , 也在该步骤中进行修改 ;
  • 再后 , 删除旧的数据库表 Table 表 ;
  • 最后 , 将 临时数据库表 Temp_Table 表 重命名为 Table 表 ;




二、销毁 和 重建策略 核心要点




1、创建 Migration 迁移类 - 重点


在本篇博客中 , 在之前的博客

基础上 , 升级数据库版本 4 ;

数据库 版本 2 和 3 分别在 数据库 版本 1 的基础上新增了一个字段 ;

这里要升级的数据库版本 4 , 要 在 数据库版本 3 的基础上 , 将 integer 类型的字段 sex 的 数据类型 修改为 text 类型 ,

这就需要将 整个数据库表中的数据的 指定字段 需要重新赋值 ;

这就需要 使用 销毁重建 策略 ;


销毁 和 重建策略 执行步骤 :

  • 首先 , 创建一张 符合 新数据库表结构 的 临时数据库表;
                // 创新临时数据库
                database.execSQL(
                    "CREATE TABLE temp_student (" +
                            "id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL," +
                            "name TEXT," +
                            "age INTEGER NOT NULL," +
                            "sex TEXT DEFAULT 'M'," +
                            "degree INTEGER NOT NULL DEFAULT 1)"
                )

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 然后 , 将 旧数据库表 中的数据 拷贝到 临时数据库表 中 , 如果需要修改 , 也在该步骤中进行修改 ;
                // 拷贝数据
                database.execSQL(
                    "INSERT INTO temp_student (name,age,degree)" +
                            "SELECT name,age,degree FROM student"
                )

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 再后 , 删除旧的数据库表 ;
                // 删除原始表
                database.execSQL("DROP TABLE student")

 
 
  • 1
  • 2
  • 最后 , 将 临时数据库表 重命名为 原来的表名 ;
                // 将临时表命令为原表表明
                database.execSQL("ALTER TABLE temp_student RENAME TO student")

 
 
  • 1
  • 2

上述的 四个步骤 , 都在 Migration 的 public void migrate(@NonNull SupportSQLiteDatabase database) 函数中完成 , 每个步骤分别对应一个 SQL 语句 ;

最终定义的 Migration 为 :

        /**
         * 数据库版本 3 升级到 版本 4 的迁移类实例对象
         * 销毁重建策略
         */
        val MIGRATION_3_4: Migration = object : Migration(3, 4) {
            override fun migrate(database: SupportSQLiteDatabase) {
                // 创新临时数据库
                database.execSQL(
                    "CREATE TABLE temp_student (" +
                            "id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL," +
                            "name TEXT," +
                            "age INTEGER NOT NULL," +
                            "sex TEXT DEFAULT 'M'," +
                            "degree INTEGER NOT NULL DEFAULT 1)"
                )
            <span class="token comment">// 拷贝数据</span>
            database<span class="token punctuation">.</span><span class="token function">execSQL</span><span class="token punctuation">(</span>
                <span class="token string-literal singleline"><span class="token string">"INSERT INTO temp_student (name,age,degree)"</span></span> <span class="token operator">+</span>
                        <span class="token string-literal singleline"><span class="token string">"SELECT name,age,degree FROM student"</span></span>
            <span class="token punctuation">)</span>

            <span class="token comment">// 删除原始表</span>
            database<span class="token punctuation">.</span><span class="token function">execSQL</span><span class="token punctuation">(</span><span class="token string-literal singleline"><span class="token string">"DROP TABLE student"</span></span><span class="token punctuation">)</span>

            <span class="token comment">// 将临时表命令为原表表明</span>
            database<span class="token punctuation">.</span><span class="token function">execSQL</span><span class="token punctuation">(</span><span class="token string-literal singleline"><span class="token string">"ALTER TABLE temp_student RENAME TO student"</span></span><span class="token punctuation">)</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

2、配置 Migration 迁移类


创建 RoomDatabase.Builder 时 , 调用 RoomDatabase.Builder#addMigrations , 设置上述创建的 销毁重建策略的 Migration 迁移类 ;

        fun inst(context: Context): StudentDatabase {
            if (!::instance.isInitialized) {
                synchronized(StudentDatabase::class) {
                    // 创建数据库
                    instance = Room.databaseBuilder(
                        context.applicationContext,
                        StudentDatabase::class.java,
                        "student_database.db")
                        .addMigrations(MIGRATION_1_2)
                        .addMigrations(MIGRATION_2_3)
                        .addMigrations(MIGRATION_3_4)
                        .fallbackToDestructiveMigration()
                        .allowMainThreadQueries() // Room 原则上不允许在主线程操作数据库
                                                  // 如果要在主线程操作数据库需要调用该函数
                        .build()
                }
            }
            return instance;
        }

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

3、修改数据库版本号


在 RoomDatabase 类的 @Database 注解上的 version 数据库版本号参数设置为 4 ;

@Database(entities = [Student::class], version = 4, exportSchema = true)
abstract class StudentDatabase: RoomDatabase() {

 
 
  • 1
  • 2

4、修改实体类数据类型


将 Entity 实体类 Student 类中的 sex 字段 由

    /**
     * 性别字段
     * 数据库表中的列名为 sex
     * 数据库表中的类型为 INTEGER 文本类型
     */
    @ColumnInfo(name = "sex", typeAffinity = ColumnInfo.INTEGER)
    var sex: Int = 0

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

修改为 :

    /**
     * 性别字段
     * 数据库表中的列名为 sex
     * 数据库表中的类型为 TEXT 文本类型
     */
    @ColumnInfo(name = "sex", typeAffinity = ColumnInfo.TEXT)
    var sex: String = "M"

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7




三、完整代码示例



代码地址 : https://github.com/han1202012/Room_ViewModel_LiveData


1、数据库版本 3 代码示例


RoomDatabase 数据库类完整代码

package kim.hsl.rvl

import android.content.Context
import android.util.Log
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase

@Database(entities = [Student::class], version = 3, exportSchema = true)
abstract class StudentDatabase: RoomDatabase() {
/**
* 获取 数据库访问 对象
* 这是必须要实现的函数
*/

abstract fun studentDao(): StudentDao

<span class="token keyword">companion</span> <span class="token keyword">object</span> <span class="token punctuation">{<!-- --></span>
    <span class="token keyword">lateinit</span> <span class="token keyword">var</span> instance<span class="token operator">:</span> StudentDatabase

    <span class="token comment">/**
     * 数据库版本 1 升级到 版本 2 的迁移类实例对象
     */</span>
    <span class="token keyword">val</span> MIGRATION_1_2<span class="token operator">:</span> Migration <span class="token operator">=</span> <span class="token keyword">object</span> <span class="token operator">:</span> <span class="token function">Migration</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
        <span class="token keyword">override</span> <span class="token keyword">fun</span> <span class="token function">migrate</span><span class="token punctuation">(</span>database<span class="token operator">:</span> SupportSQLiteDatabase<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
            Log<span class="token punctuation">.</span><span class="token function">i</span><span class="token punctuation">(</span><span class="token string-literal singleline"><span class="token string">"Room_StudentDatabase"</span></span><span class="token punctuation">,</span> <span class="token string-literal singleline"><span class="token string">"数据库版本 1 升级到 版本 2"</span></span><span class="token punctuation">)</span>
            database<span class="token punctuation">.</span><span class="token function">execSQL</span><span class="token punctuation">(</span><span class="token string-literal singleline"><span class="token string">"alter table student add column sex integer not null default 1"</span></span><span class="token punctuation">)</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>

    <span class="token comment">/**
     * 数据库版本 2 升级到 版本 3 的迁移类实例对象
     */</span>
    <span class="token keyword">val</span> MIGRATION_2_3<span class="token operator">:</span> Migration <span class="token operator">=</span> <span class="token keyword">object</span> <span class="token operator">:</span> <span class="token function">Migration</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
        <span class="token keyword">override</span> <span class="token keyword">fun</span> <span class="token function">migrate</span><span class="token punctuation">(</span>database<span class="token operator">:</span> SupportSQLiteDatabase<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
            Log<span class="token punctuation">.</span><span class="token function">i</span><span class="token punctuation">(</span><span class="token string-literal singleline"><span class="token string">"Room_StudentDatabase"</span></span><span class="token punctuation">,</span> <span class="token string-literal singleline"><span class="token string">"数据库版本 2 升级到 版本 3"</span></span><span class="token punctuation">)</span>
            database<span class="token punctuation">.</span><span class="token function">execSQL</span><span class="token punctuation">(</span><span class="token string-literal singleline"><span class="token string">"alter table student add column degree integer not null default 1"</span></span><span class="token punctuation">)</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">fun</span> <span class="token function">inst</span><span class="token punctuation">(</span>context<span class="token operator">:</span> Context<span class="token punctuation">)</span><span class="token operator">:</span> StudentDatabase <span class="token punctuation">{<!-- --></span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token operator">::</span>instance<span class="token punctuation">.</span>isInitialized<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
            <span class="token function">synchronized</span><span class="token punctuation">(</span>StudentDatabase<span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
                <span class="token comment">// 创建数据库</span>
                instance <span class="token operator">=</span> Room<span class="token punctuation">.</span><span class="token function">databaseBuilder</span><span class="token punctuation">(</span>
                    context<span class="token punctuation">.</span>applicationContext<span class="token punctuation">,</span>
                    StudentDatabase<span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">.</span>java<span class="token punctuation">,</span>
                    <span class="token string-literal singleline"><span class="token string">"student_database.db"</span></span><span class="token punctuation">)</span>
                    <span class="token punctuation">.</span><span class="token function">addMigrations</span><span class="token punctuation">(</span>MIGRATION_1_2<span class="token punctuation">)</span>
                    <span class="token punctuation">.</span><span class="token function">addMigrations</span><span class="token punctuation">(</span>MIGRATION_2_3<span class="token punctuation">)</span>
                    <span class="token punctuation">.</span><span class="token function">fallbackToDestructiveMigration</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
                    <span class="token punctuation">.</span><span class="token function">allowMainThreadQueries</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// Room 原则上不允许在主线程操作数据库</span>
                                              <span class="token comment">// 如果要在主线程操作数据库需要调用该函数</span>
                    <span class="token punctuation">.</span><span class="token function">build</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>
        <span class="token keyword">return</span> instance<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61

Student 实体类完整代码

package kim.hsl.rvl

import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.Ignore
import androidx.room.PrimaryKey

/**

  • 定义数据库表 Entity 实体 / 同时定义数据库表 和 对鹰的实体类

  • 设置该数据类对应数据库中的一张数据表, 表名为 student

  • 该数据库表中的数据对应一个 Student 类实例对象
    /
    @Entity(tableName = “student”)
    class Student {
    /
    *

    • @PrimaryKey 设置主键 autoGenerate 为自增
    • @ColumnInfo name 设置列名称 / typeAffinity 设置列类型
      */
      @PrimaryKey(autoGenerate = true)
      @ColumnInfo(name = “id”, typeAffinity = ColumnInfo.INTEGER)
      var id: Int = 0

    /**

    • 姓名字段
    • 数据库表中的列名为 name
    • 数据库表中的类型为 TEXT 文本类型
      */
      @ColumnInfo(name = “name”, typeAffinity = ColumnInfo.TEXT)
      lateinit var name: String

    /**

    • 年龄字段
    • 数据库表中的列名为 age
    • 数据库表中的类型为 INTEGER 文本类型
      */
      @ColumnInfo(name = “age”, typeAffinity = ColumnInfo.INTEGER)
      var age: Int = 0

    /**

    • 性别字段
    • 数据库表中的列名为 sex
    • 数据库表中的类型为 INTEGER 文本类型
      */
      @ColumnInfo(name = “sex”, typeAffinity = ColumnInfo.INTEGER)
      var sex: Int = 0

    /**

    • degree字段
    • 数据库表中的列名为 sex
    • 数据库表中的类型为 INTEGER 文本类型
      */
      @ColumnInfo(name = “degree”, typeAffinity = ColumnInfo.INTEGER)
      var degree: Int = 0

    /**

    • 有些属性用于做业务逻辑
    • 不需要插入到数据库中
    • 使用 @Ignore 注解修饰该属性字段
      */
      @Ignore
      lateinit var studentInfo: String

    /**

    • 默认的构造方法给 Room 框架使用
      */
      constructor(id: Int, name: String, age: Int) {
      this.id = id
      this.name = name
      this.age = age
      }

    /**

    • 使用 @Ignore 标签标注后
    • Room 就不会使用该构造方法了
    • 这个构造方法是给开发者使用的
      */
      @Ignore
      constructor(name: String, age: Int) {
      this.name = name
      this.age = age
      }

    /**

    • 使用 @Ignore 标签标注后
    • Room 就不会使用该构造方法了
    • 这个构造方法是给开发者使用的
      */
      @Ignore
      constructor(id: Int) {
      this.id = id
      }

    override fun toString(): String {
    return “Student(id= < / s p a n > < s p a n c l a s s = " t o k e n e x p r e s s i o n " > i d < / s p a n > < / s p a n > < s p a n c l a s s = " t o k e n s t r i n g " > , n a m e = ′ < / s p a n > < s p a n c l a s s = " t o k e n i n t e r p o l a t i o n " > < s p a n c l a s s = " t o k e n i n t e r p o l a t i o n − p u n c t u a t i o n p u n c t u a t i o n " > </span><span class="token expression">id</span></span><span class="token string">, name='</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation"> </span><spanclass="tokenexpression">id</span></span><spanclass="tokenstring">,name=</span><spanclass="tokeninterpolation"><spanclass="tokeninterpolationpunctuationpunctuation">name', age=$age)”
    }
    }

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96

执行结果

先执行数据库版本为 3 的应用 , 输出结果如下 :

2023-06-05 19:17:12.251 I/Room_MainActivity: Observer#onChanged 回调, List<Student>: []
2023-06-05 19:17:12.532 I/Room_MainActivity: 插入数据 S1 : Student(id=0, name='Tom', age=18)
2023-06-05 19:17:12.536 I/Room_MainActivity: Observer#onChanged 回调, List<Student>: [Student(id=1, name='Tom', age=18)]
2023-06-05 19:17:13.036 I/Room_MainActivity: 插入数据 S2 : Student(id=0, name='Jerry', age=16)
2023-06-05 19:17:13.038 I/Room_MainActivity: Observer#onChanged 回调, List<Student>: [Student(id=1, name='Tom', age=18), Student(id=2, name='Jerry', age=16)]
2023-06-05 19:17:13.538 I/Room_MainActivity: 更新数据 S2 : Student(id=2, name='Jack', age=60)
2023-06-05 19:17:13.540 I/Room_MainActivity: Observer#onChanged 回调, List<Student>: [Student(id=1, name='Tom', age=18), Student(id=2, name='Jack', age=60)]
2023-06-05 19:17:14.051 I/Room_MainActivity: 删除数据 id = 1
2023-06-05 19:17:14.060 I/Room_MainActivity: Observer#onChanged 回调, List<Student>: [Student(id=2, name='Jack', age=60)]
2023-06-05 19:17:14.553 I/Room_MainActivity: 主动查询 : LiveData : androidx.room.RoomTrackingLiveData@8726677 , 实际数据 : null
2023-06-05 19:17:14.554 I/Room_MainActivity: 主动查询2 : [Student(id=2, name='Jack', age=60)]

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

在这里插入图片描述


2、数据库版本 4 代码示例


将数据库版本修改为 4 , 然后执行上述 销毁重建策略 修改 ;

主要是创建了 数据库版本 3 升级到 版本 4 的迁移类实例对象 , 该 Migration 类

RoomDatabase 数据库类完整代码

package kim.hsl.rvl

import android.content.Context
import android.util.Log
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase

@Database(entities = [Student::class], version = 4, exportSchema = true)
abstract class StudentDatabase: RoomDatabase() {
/**
* 获取 数据库访问 对象
* 这是必须要实现的函数
*/

abstract fun studentDao(): StudentDao

<span class="token keyword">companion</span> <span class="token keyword">object</span> <span class="token punctuation">{<!-- --></span>
    <span class="token keyword">lateinit</span> <span class="token keyword">var</span> instance<span class="token operator">:</span> StudentDatabase

    <span class="token comment">/**
     * 数据库版本 1 升级到 版本 2 的迁移类实例对象
     */</span>
    <span class="token keyword">val</span> MIGRATION_1_2<span class="token operator">:</span> Migration <span class="token operator">=</span> <span class="token keyword">object</span> <span class="token operator">:</span> <span class="token function">Migration</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
        <span class="token keyword">override</span> <span class="token keyword">fun</span> <span class="token function">migrate</span><span class="token punctuation">(</span>database<span class="token operator">:</span> SupportSQLiteDatabase<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
            Log<span class="token punctuation">.</span><span class="token function">i</span><span class="token punctuation">(</span><span class="token string-literal singleline"><span class="token string">"Room_StudentDatabase"</span></span><span class="token punctuation">,</span> <span class="token string-literal singleline"><span class="token string">"数据库版本 1 升级到 版本 2"</span></span><span class="token punctuation">)</span>
            database<span class="token punctuation">.</span><span class="token function">execSQL</span><span class="token punctuation">(</span><span class="token string-literal singleline"><span class="token string">"alter table student add column sex integer not null default 1"</span></span><span class="token punctuation">)</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>

    <span class="token comment">/**
     * 数据库版本 2 升级到 版本 3 的迁移类实例对象
     */</span>
    <span class="token keyword">val</span> MIGRATION_2_3<span class="token operator">:</span> Migration <span class="token operator">=</span> <span class="token keyword">object</span> <span class="token operator">:</span> <span class="token function">Migration</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
        <span class="token keyword">override</span> <span class="token keyword">fun</span> <span class="token function">migrate</span><span class="token punctuation">(</span>database<span class="token operator">:</span> SupportSQLiteDatabase<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
            Log<span class="token punctuation">.</span><span class="token function">i</span><span class="token punctuation">(</span><span class="token string-literal singleline"><span class="token string">"Room_StudentDatabase"</span></span><span class="token punctuation">,</span> <span class="token string-literal singleline"><span class="token string">"数据库版本 2 升级到 版本 3"</span></span><span class="token punctuation">)</span>
            database<span class="token punctuation">.</span><span class="token function">execSQL</span><span class="token punctuation">(</span><span class="token string-literal singleline"><span class="token string">"alter table student add column degree integer not null default 1"</span></span><span class="token punctuation">)</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>

    <span class="token comment">/**
     * 数据库版本 3 升级到 版本 4 的迁移类实例对象
     * 销毁重建策略
     */</span>
    <span class="token keyword">val</span> MIGRATION_3_4<span class="token operator">:</span> Migration <span class="token operator">=</span> <span class="token keyword">object</span> <span class="token operator">:</span> <span class="token function">Migration</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
        <span class="token keyword">override</span> <span class="token keyword">fun</span> <span class="token function">migrate</span><span class="token punctuation">(</span>database<span class="token operator">:</span> SupportSQLiteDatabase<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
            Log<span class="token punctuation">.</span><span class="token function">i</span><span class="token punctuation">(</span><span class="token string-literal singleline"><span class="token string">"Room_StudentDatabase"</span></span><span class="token punctuation">,</span> <span class="token string-literal singleline"><span class="token string">"数据库版本 3 升级到 版本 4"</span></span><span class="token punctuation">)</span>
            <span class="token comment">// 创新临时数据库</span>
            database<span class="token punctuation">.</span><span class="token function">execSQL</span><span class="token punctuation">(</span>
                <span class="token string-literal singleline"><span class="token string">"CREATE TABLE temp_student ("</span></span> <span class="token operator">+</span>
                        <span class="token string-literal singleline"><span class="token string">"id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,"</span></span> <span class="token operator">+</span>
                        <span class="token string-literal singleline"><span class="token string">"name TEXT,"</span></span> <span class="token operator">+</span>
                        <span class="token string-literal singleline"><span class="token string">"age INTEGER NOT NULL,"</span></span> <span class="token operator">+</span>
                        <span class="token string-literal singleline"><span class="token string">"sex TEXT NOT NULL DEFAULT 'M',"</span></span> <span class="token operator">+</span>
                        <span class="token string-literal singleline"><span class="token string">"degree INTEGER NOT NULL DEFAULT 1)"</span></span>
            <span class="token punctuation">)</span>

            <span class="token comment">// 拷贝数据</span>
            database<span class="token punctuation">.</span><span class="token function">execSQL</span><span class="token punctuation">(</span>
                <span class="token string-literal singleline"><span class="token string">"INSERT INTO temp_student (name, age, degree)"</span></span> <span class="token operator">+</span>
                        <span class="token string-literal singleline"><span class="token string">"SELECT name, age, degree FROM student"</span></span>
            <span class="token punctuation">)</span>

            <span class="token comment">// 删除原始表</span>
            database<span class="token punctuation">.</span><span class="token function">execSQL</span><span class="token punctuation">(</span><span class="token string-literal singleline"><span class="token string">"DROP TABLE student"</span></span><span class="token punctuation">)</span>

            <span class="token comment">// 将临时表命令为原表表明</span>
            database<span class="token punctuation">.</span><span class="token function">execSQL</span><span class="token punctuation">(</span><span class="token string-literal singleline"><span class="token string">"ALTER TABLE temp_student RENAME TO student"</span></span><span class="token punctuation">)</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">fun</span> <span class="token function">inst</span><span class="token punctuation">(</span>context<span class="token operator">:</span> Context<span class="token punctuation">)</span><span class="token operator">:</span> StudentDatabase <span class="token punctuation">{<!-- --></span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token operator">::</span>instance<span class="token punctuation">.</span>isInitialized<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
            <span class="token function">synchronized</span><span class="token punctuation">(</span>StudentDatabase<span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
                <span class="token comment">// 创建数据库</span>
                instance <span class="token operator">=</span> Room<span class="token punctuation">.</span><span class="token function">databaseBuilder</span><span class="token punctuation">(</span>
                    context<span class="token punctuation">.</span>applicationContext<span class="token punctuation">,</span>
                    StudentDatabase<span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">.</span>java<span class="token punctuation">,</span>
                    <span class="token string-literal singleline"><span class="token string">"student_database.db"</span></span><span class="token punctuation">)</span>
                    <span class="token punctuation">.</span><span class="token function">addMigrations</span><span class="token punctuation">(</span>MIGRATION_1_2<span class="token punctuation">)</span>
                    <span class="token punctuation">.</span><span class="token function">addMigrations</span><span class="token punctuation">(</span>MIGRATION_2_3<span class="token punctuation">)</span>
                    <span class="token punctuation">.</span><span class="token function">addMigrations</span><span class="token punctuation">(</span>MIGRATION_3_4<span class="token punctuation">)</span>
                    <span class="token punctuation">.</span><span class="token function">fallbackToDestructiveMigration</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
                    <span class="token punctuation">.</span><span class="token function">allowMainThreadQueries</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// Room 原则上不允许在主线程操作数据库</span>
                                              <span class="token comment">// 如果要在主线程操作数据库需要调用该函数</span>
                    <span class="token punctuation">.</span><span class="token function">build</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>
        <span class="token keyword">return</span> instance<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93

Student 实体类代码示例

package kim.hsl.rvl

import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.Ignore
import androidx.room.PrimaryKey

/**

  • 定义数据库表 Entity 实体 / 同时定义数据库表 和 对鹰的实体类

  • 设置该数据类对应数据库中的一张数据表, 表名为 student

  • 该数据库表中的数据对应一个 Student 类实例对象
    /
    @Entity(tableName = “student”)
    class Student {
    /
    *

    • @PrimaryKey 设置主键 autoGenerate 为自增
    • @ColumnInfo name 设置列名称 / typeAffinity 设置列类型
      */
      @PrimaryKey(autoGenerate = true)
      @ColumnInfo(name = “id”, typeAffinity = ColumnInfo.INTEGER)
      var id: Int = 0

    /**

    • 姓名字段
    • 数据库表中的列名为 name
    • 数据库表中的类型为 TEXT 文本类型
      */
      @ColumnInfo(name = “name”, typeAffinity = ColumnInfo.TEXT)
      lateinit var name: String

    /**

    • 年龄字段
    • 数据库表中的列名为 age
    • 数据库表中的类型为 INTEGER 文本类型
      */
      @ColumnInfo(name = “age”, typeAffinity = ColumnInfo.INTEGER)
      var age: Int = 0

    /**

    • 性别字段
    • 数据库表中的列名为 sex
    • 数据库表中的类型为 TEXT 文本类型
      */
      @ColumnInfo(name = “sex”, typeAffinity = ColumnInfo.TEXT)
      var sex: String = “M”

    /**

    • 性别字段
    • 数据库表中的列名为 sex
    • 数据库表中的类型为 INTEGER 文本类型
      /
      /
      @ColumnInfo(name = “sex”, typeAffinity = ColumnInfo.INTEGER)
      var sex: Int = 0*/

    /**

    • degree字段
    • 数据库表中的列名为 sex
    • 数据库表中的类型为 INTEGER 文本类型
      */
      @ColumnInfo(name = “degree”, typeAffinity = ColumnInfo.INTEGER)
      var degree: Int = 0

    /**

    • 有些属性用于做业务逻辑
    • 不需要插入到数据库中
    • 使用 @Ignore 注解修饰该属性字段
      */
      @Ignore
      lateinit var studentInfo: String

    /**

    • 默认的构造方法给 Room 框架使用
      */
      constructor(id: Int, name: String, age: Int) {
      this.id = id
      this.name = name
      this.age = age
      }

    /**

    • 使用 @Ignore 标签标注后
    • Room 就不会使用该构造方法了
    • 这个构造方法是给开发者使用的
      */
      @Ignore
      constructor(name: String, age: Int) {
      this.name = name
      this.age = age
      }

    /**

    • 使用 @Ignore 标签标注后
    • Room 就不会使用该构造方法了
    • 这个构造方法是给开发者使用的
      */
      @Ignore
      constructor(id: Int) {
      this.id = id
      }

    override fun toString(): String {
    return “Student(id= < / s p a n > < s p a n c l a s s = " t o k e n e x p r e s s i o n " > i d < / s p a n > < / s p a n > < s p a n c l a s s = " t o k e n s t r i n g " > , n a m e = ′ < / s p a n > < s p a n c l a s s = " t o k e n i n t e r p o l a t i o n " > < s p a n c l a s s = " t o k e n i n t e r p o l a t i o n − p u n c t u a t i o n p u n c t u a t i o n " > </span><span class="token expression">id</span></span><span class="token string">, name='</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation"> </span><spanclass="tokenexpression">id</span></span><spanclass="tokenstring">,name=</span><spanclass="tokeninterpolation"><spanclass="tokeninterpolationpunctuationpunctuation">name', age=$age)”
    }
    }

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104

执行结果

执行结果如下 :

2023-06-05 19:18:58.864 I/Room_StudentDatabase: 数据库版本 3 升级到 版本 4
2023-06-05 19:18:58.909 I/Room_MainActivity: Observer#onChanged 回调, List<Student>: [Student(id=1, name='Jack', age=60)]
2023-06-05 19:18:59.346 I/Room_MainActivity: 插入数据 S1 : Student(id=0, name='Tom', age=18)
2023-06-05 19:18:59.351 I/Room_MainActivity: Observer#onChanged 回调, List<Student>: [Student(id=1, name='Jack', age=60), Student(id=2, name='Tom', age=18)]
2023-06-05 19:18:59.853 I/Room_MainActivity: 插入数据 S2 : Student(id=0, name='Jerry', age=16)
2023-06-05 19:18:59.855 I/Room_MainActivity: Observer#onChanged 回调, List<Student>: [Student(id=1, name='Jack', age=60), Student(id=2, name='Tom', age=18), Student(id=3, name='Jerry', age=16)]
2023-06-05 19:19:00.362 I/Room_MainActivity: 更新数据 S2 : Student(id=2, name='Jack', age=60)
2023-06-05 19:19:00.371 I/Room_MainActivity: Observer#onChanged 回调, List<Student>: [Student(id=1, name='Jack', age=60), Student(id=2, name='Jack', age=60), Student(id=3, name='Jerry', age=16)]
2023-06-05 19:19:00.875 I/Room_MainActivity: 删除数据 id = 1
2023-06-05 19:19:00.877 I/Room_MainActivity: Observer#onChanged 回调, List<Student>: [Student(id=2, name='Jack', age=60), Student(id=3, name='Jerry', age=16)]
2023-06-05 19:19:01.377 I/Room_MainActivity: 主动查询 : LiveData : androidx.room.RoomTrackingLiveData@b957950 , 实际数据 : null
2023-06-05 19:19:01.378 I/Room_MainActivity: 主动查询2 : [Student(id=2, name='Jack', age=60), Student(id=3, name='Jerry', age=16)]

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

在这里插入图片描述

对于 Room 数据库的升级,您需要遵循以下步骤: 1. 在新版本的数据库定义新结构或对旧表结构进行更改,例如添加、删除或修改的列。 2. 在您的 `AppDatabase` 类增加数据库版本号,可以在类上使用 `@Database` 注解指定版本号,例如: ```kotlin @Database(entities = [User::class], version = 2) abstract class AppDatabase : RoomDatabase() { //... } ``` 3. 创建一个实现 `Migration` 接口的类,该类将包含从旧版本升级到新版本所需的所有更改。例如: ```kotlin val migration_1_2 = object : Migration(1, 2) { override fun migrate(database: SupportSQLiteDatabase) { database.execSQL("ALTER TABLE users ADD COLUMN age INTEGER NOT NULL DEFAULT 0") } } ``` 该示例代码示,从版本 1 升级到版本 2,需要在 `users` 添加一个名为 `age` 的整数类型的列。 4. 在 `AppDatabase` 类,使用 `addMigrations()` 方法将 `Migration` 对象添加到数据库,例如: ```kotlin @Database(entities = [User::class], version = 2) abstract class AppDatabase : RoomDatabase() { //... companion object { val migration_1_2 = object : Migration(1, 2) { override fun migrate(database: SupportSQLiteDatabase) { database.execSQL("ALTER TABLE users ADD COLUMN age INTEGER NOT NULL DEFAULT 0") } } } //... init { if (BuildConfig.DEBUG) { // 在调试模式下,如果发现数据结构变化,将会清空数据 fallbackToDestructiveMigration() } else { // 在正式发布模式下,如果发现数据结构变化,将会执行升级脚本 addMigrations(migration_1_2) } } } ``` 在上述示例代码,我们将 `migration_1_2` 对象添加到 `AppDatabase` 类的伴生对象,并在 `init` 块进行了初始化。我们还使用了 `fallbackToDestructiveMigration()` 方法,如果在调试模式下发现数据结构变化,将会清空数据。在正式发布模式下,我们使用了 `addMigrations()` 方法,将 `migration_1_2` 对象添加到数据库,以执行升级脚本。 这样,在您的应用程序使用新版本的数据库时,将自动执行升级脚本,以将旧数据结构转换为新数据结构。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值