电子商务网站开发 刘兰娟,企业网站建设发展平台,榨油机 东莞网站建设,中国域名门户网站room数据库升级
一、操作步骤说明 增加数据库版本号 在Database注解中增加版本号(version)#xff0c;比如从version 1升级到version 2。 Database(entities [Song::class,],**version 1**,//1-2
)
abstract class AppDataBase : RoomDatabase() {
}定义数据库变化 根据…room数据库升级
一、操作步骤说明 增加数据库版本号 在Database注解中增加版本号(version)比如从version 1升级到version 2。 Database(entities [Song::class,],**version 1**,//1-2
)
abstract class AppDataBase : RoomDatabase() {
}定义数据库变化 根据需要修改的内容添加表、修改表、删除表等更新对应的Entity类和DAO接口 创建Migration对象 创建一个Migration对象该对象定义了数据库从旧版本升级到新版本时需要执行的操作。实现migrate()方法编写SQL语句来处理结构变化或数据迁移 private val MIGRATION_1_2 object : Migration(1, 2) {override fun migrate(database: SupportSQLiteDatabase) {//升级操作}} 配置数据库实例 在创建Room数据库实例时通过.addMigrations()方法添加上一步创建的Migration对象。如果有多个版本的迁移可以链式调用.addMigrations()添加多个Migration对象。 var appDatabase Room.databaseBuilder(context,AppDataBase::class.java,DATABASE_NAME,).apply {// 把初始下载权限表放这里了createFromAsset(init.db)addMigrations(MIGRATION_1_2, )}测试迁移 使用单元测试来确保Migration正确无误地执行了预期的数据库变化。测试包括但不限于表结构变化、数据迁移的正确性、数据完整性等。
二、常见升级
表定义
Entity(tableName t_song)
data class Song(PrimaryKeyColumnInfo(name song_id)val songId: String,//歌曲idColumnInfo(name name)val songName: String,//歌曲名称ColumnInfo(name type)val songType: Int,//歌曲类型1:歌曲 2:听书
)2.1 增加一个普通字段、索引
2.1.1 Entity类修改
Entity(tableName t_song)
data class Song(PrimaryKeyColumnInfo(name song_id)val songId: String,//歌曲idColumnInfo(name name)val songName: String,//歌曲名称ColumnInfo(name type)val songType: Int,//歌曲类型1:歌曲 2:听书//新增albumId字段且创建索引ColumnInfo(name album_idindex true)val albumId: String?null,//专辑id
)2.1.1 旧版本升级兼容即创建Migration对象,
private val MIGRATION_1_2 object : Migration(1, 2) {override fun migrate(database: SupportSQLiteDatabase) {//升级操作//增加url字段database.execSQL(ALTER TABLE t_songs ADD COLUMN album_id TEXT)//增加索引database.execSQL(CREATE INDEX IF NOT EXISTS index_t_songs_album_id ON t_songs (album_id))}}2.2 删除表
2.2.1 移除Entity和DAO
从代码中移除Entity注解的Song类假设Song是对应t_songs表的Entity。同时移除与Song类相关的DAO接口。
2.2.2 删除旧表
private val MIGRATION_1_2 object : Migration(1, 2) {override fun migrate(database: SupportSQLiteDatabase) {//升级操作// 删除t_songs表database.execSQL(DROP TABLE IF EXISTS t_songs)}}t_songs表数据有几百万条时执行DROP TABLE IF EXISTS t_songs 会很耗时经测试400w条时就会达到十几秒。在升级时会阻塞数据库的操作进而影响业务的处理很可能导致UI界面加载不出数据一直转圈圈。所以我们可以采用在数据库升级时即migrate()不删除废弃的表而是在业务中
开启一个线程每1000条的删除数据当数据删除完后删除t_songs表
代码如下
class MainViewModel{Injectlateinit var appDataBase: LazyAppDataBase,fun deleteTSong(){viewModelScope.launch(Dispatchers.IO) {val count getTSongsCount()if(count 0){val page count / 1000 1//大概率不会整除直接1val writableDatabase: SupportSQLiteDatabase appDataBase.get().openHelper.writableDatabaserepeat(page) {//这里的分页删除好傻,耗时毫秒级writableDatabase.execSQL(DELETE FROM t_songs WHERE song_id IN (SELECT song_id FROM t_songs LIMIT 1000))//重点 这里延迟120ms是为了这里删除不要独占数据库操作如果不理解 想想cpu时间片delay(120)}//没数据了就删除表appDataBase.get().openHelper.writableDatabase.execSQL(DROP TABLE IF EXISTS t_songs}}}/*** 获取t_songs表大小*/private suspend fun getTSongsCount(): Int {return withContext(Dispatchers.IO) {var count -1runCatching{appDataBase.get().query(SELECT count(*) FROM t_songs_temp, null).use {if (it.moveToFirst()) {count it.getInt(0)}}} count}}
}2.3 修改字段名或者类型或者增加主键
针对这种不能在旧表上修改的需求我们只能新建一个新表然后把旧表中的数据复制到新表中——销毁重新。
例如我们的t_songs 增加了一个曲库比如tme, 这时song_id就可能在两个曲库中重复了所以要增加sourceId表示曲库idsong_id source_id 一起作为主键。
2.3.1 修改Entity
Entity(tableName t_song, primaryKeys [song_id,song_type,source_id])
data class Song(ColumnInfo(name song_id)val songId: String,//歌曲idColumnInfo(name name)val songName: String,//歌曲名称ColumnInfo(name type)val songType: Int,//歌曲类型1:歌曲 2:听书//增加source_idColumnInfo(name source_id)val sourceId: Int,//曲库id)2.3.2 旧版本升级兼容——销毁重建
有两种方案
方案一、
创建一个新表创建一个新表其结构与原表相同除了需要修改的字段名。复制数据将原表中的数据复制到新表中同时将需要修改的字段名的数据赋值到新的列名。删除原表删除原始的表。重命名新表将新表重命名为原始表的名字。
方案二、
重命名旧表将原始表重命名为t_songs_old创建一个新表创建一个新表其结构与原表相同除了需要修改的字段名。复制数据将原表中的数据复制到新表中同时将需要修改的字段名的数据赋值到新的列名。删除原表删除原始的表。
我们可以看到方案二如果不执行第4步我们可以通过App Inspection查看迁移前后的表方便我们调试还有就是第4步 如果旧表中数据量很大时可以把步骤4放在业务中进行慢慢删除综上 推荐方案二。
private val MIGRATION_1_2 object : Migration(1, 2) {override fun migrate(database: SupportSQLiteDatabase) {//1. 重命名旧表database.execSQL(ALTER TABLE t_songs RENAME TO t_songs_temp)//2. 如果有索引则删除旧表的索引database.execSQL(DROP INDEX index_t_songs_album_id)//3. 创建新表这里的语句建议查看自动生成AppData_Imp类里的代码复制过来防止自己写错了database.execSQL(CREATE TABLE IF NOT EXISTS t_song (song_id TEXT NOT NULL, song_id TEXT NOT NULL, name TEXT NOT NULL, source_id INTEGER NOT NULL, PRIMARY KEY(song_id, source_id)))//4. 如果旧表有索引则再建一个索引database.execSQL(CREATE INDEX IF NOT EXISTS index_t_songs_album_id ON t_songs (album_id))//5.复制数据database.execSQL(INSERT OR REPLACE INTO t_songs (song_id,song_name,song_type,source_id) SELECT song_id,song_name,song_type,0 AS source_id FROM t_songs_old)//6.删除原表database.execSQL(DROP TABLE IF EXISTS t_songs_old)}
}如果第6点很耗时建议参考2.2节如果数据量很大第5步也会很耗时建议只迁移表中有用的数据(有时候业务中只会把数据缓存到表中不删除这是表中有用数据很少建议联表进行查询出有用数据进行迁移)