android 更新本地数据库而不影响旧的数据库,同时上传应用程序到Playstore

tnkciper  于 2023-02-17  发布在  Android
关注(0)|答案(1)|浏览(204)

我在本地数据库中有2个字段(例如:名称、密码)。现在我把应用程序上传到Play商店。之后,我在数据库中添加了一个字段,即移动的号码。所以现在数据库有3个字段(即姓名、密码、移动的号码)。现在,如果我把这个应用程序上传到Play商店会发生什么?2它会影响老用户的数据库吗?我怎样才能在不影响用户的旧本地数据库的情况下更新该数据库?我正在使用Room Database

xytpbqjk

xytpbqjk1#

除非是不同的应用程序,否则更新将通过PlayStore向老用户推出。
你必须更新老用户,否则应用程序会崩溃。不过,你可以保留他们的数据,但你必须迎合新的专栏。
由于模式已更改(新列),并且如果没有迁移,则老用户将遇到崩溃,因为Room会根据@Entity注解类(预期)检查模式是否与数据库(发现)一致。

  • 崩溃将沿着以下路线进行: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. Expected identity hash: e843da3b4913dbc08880c558d759fe82, found: d5c32de20cfd495f9eae5463c1ec7433
  • 散列将不同(预期(第1个)是按照@Entity,找到的是按照现有数据库中的架构)

你需要做的是

  • 将所述默认值设置为指示尚未提供移动号码的适当值,以及
  • 添加引入新列的迁移,以及
  • 增加版本号(这将调用迁移、执行迁移,然后处理继续到检查/打开数据库)。
  • 如果没有迁移,则会发生崩溃,例如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.
    • 演示**

以下是一个演示,它将首先使用V1的数据库创建应用程序,但不使用"移动"字段/列,然后在数据库升级到V2时迁移现有数据库。现有用户将具有一个指示无移动的值。

    • 首先**注解掉V2代码的两个版本的数据库代码(迁移不需要注解掉,但显然不存在于V1中(只需避免重复代码)):-
const val DATABASE_VERSION = 1 /*<<<<<<<<<< WILL CHANGE to 2 FOR V2 */
const val USER_TABLE_NAME = "user"
const val USER_NAME_COLUMN = "name"
const val USER_PASSWORD_COLUMN = "password"

@Entity(tableName = USER_TABLE_NAME)
data class User(
    @PrimaryKey
    @ColumnInfo(name = USER_NAME_COLUMN)
    val name: String, /* Original */
    @ColumnInfo(name = USER_PASSWORD_COLUMN)
    val password: String /* Original */ 

@Dao
interface UserDAOs {
    @Insert(onConflict = OnConflictStrategy.IGNORE)
    fun insert(user: User): Long
    @Query("SELECT * FROM user")
    fun getAllUsers(): List<User>
}

@Database(entities = [User::class], exportSchema = false, version = DATABASE_VERSION)
abstract class TheDatabase: RoomDatabase() {
    abstract fun getUserDAOs(): UserDAOs

    companion object {
        private var instance: TheDatabase?=null
        fun getInstance(context: Context): TheDatabase {
            if (instance==null) {
                instance=Room.databaseBuilder(context,TheDatabase::class.java,"the_database.db")
                    .allowMainThreadQueries() /* for brevity of the demo */
                    .build()
            }
            return instance as TheDatabase
        }
    }
}
    • 现在**加载一些V1数据的一些活动代码:-
class MainActivity : AppCompatActivity() {

    lateinit var db: TheDatabase
    lateinit var dao: UserDAOs
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        db = TheDatabase.getInstance(this)
        dao = db.getUserDAOs()
        dao.getAllUsers() /*<<<< force open the database in case no code runs (this when the version and schema checking and migration for V2 will take place ) */

        if (DATABASE_VERSION == 1) {
            dao.insert(User("Fred", "passwordFred")) /* Original */
            dao.insert(User("Mary", "passwordMary")) /* Original */
        }
        /* commented out for V1 as mobile not a field in the User */
        /*
        if (DATABASE_VERSION == 2) {
            dao.insert(User("Jane","passwordJane","1234567890"))
            dao.insert(User("John","passwordJohn","0987654321"))
            dao.insert(User("Pat","passwordPat"))
        }
        */
    }
}

运行进行全新安装(即旧用户)时,通过应用程序检查:-

  • room_master_table是存储架构散列的位置,将是找到的
  • 如所期望的,这两行存在并且具有期望值。
    • 下一步**代码更改。

数据库代码变为:-
数据库版本增加:-

const val DATABASE_VERSION = 2 /*<<<<<<<<<< WILL CHANGE to 2 FOR V2 */

添加了2个新的常量值:-

const val USER_MOBILE_COLUMN = "mobile" /*<<<<<<<<<< ADDED for V2 */
const val USER_MOBILE_DEFAULT_VALUE = "xxxxxxxxxx" /*<<<<<<<<<< ADDED for V2 */

用户类变为:-

@Entity(tableName = USER_TABLE_NAME)
data class User(
    @PrimaryKey
    @ColumnInfo(name = USER_NAME_COLUMN)
    val name: String, /* Original */
    @ColumnInfo(name = USER_PASSWORD_COLUMN)
    val password: String /* Original */ ,/*<<<<<<<<< ADDED comma FOR V2 */
    /*<<<<<<<<<< SCHEMA CHANGES FOR V2 (see comma above) >>>>>>>>>>*/
    @ColumnInfo(name = USER_MOBILE_COLUMN, defaultValue = USER_MOBILE_DEFAULT_VALUE) /*<<<<<<<<<< ADDED FOR V2 */
    val mobile: String = "not provided" /*<<<<<<<<<< ADDED for V2 (default value allows mobile to not be given for V1 code in Main Activity)*/
)

@Database注解类TheDatabase添加了迁移:-

@Database(entities = [User::class], exportSchema = false, version = DATABASE_VERSION)
abstract class TheDatabase: RoomDatabase() {
    abstract fun getUserDAOs(): UserDAOs

    companion object {
        private var instance: TheDatabase?=null
        fun getInstance(context: Context): TheDatabase {
            if (instance==null) {
                instance=Room.databaseBuilder(context,TheDatabase::class.java,"the_database.db")
                    .allowMainThreadQueries() /* for brevity of the demo */
                    .addMigrations(MIGRATE_1_to_2)
                    .build()
            }
            return instance as TheDatabase
        }
        val MIGRATE_1_to_2: Migration = object: Migration(1,2){
            override fun migrate(db: SupportSQLiteDatabase) {
                db.execSQL("ALTER TABLE $USER_TABLE_NAME ADD COLUMN $USER_MOBILE_COLUMN TEXT NOT NULL DEFAULT '$USER_MOBILE_DEFAULT_VALUE'")
                /* So as to show Migration add a row when migrating (would not be done normally) */
                val cv = ContentValues()
                cv.put(USER_NAME_COLUMN,"Alice")
                cv.put(USER_PASSWORD_COLUMN,"passwordAlice")
                cv.put(USER_MOBILE_COLUMN,"1111111111")
                db.insert(USER_TABLE_NAME,OnConflictStrategy.IGNORE,cv)
            }
        }
    }
}

注解掉的活动代码在V2中未注解:-

class MainActivity : AppCompatActivity() {

    lateinit var db: TheDatabase
    lateinit var dao: UserDAOs
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        db = TheDatabase.getInstance(this)
        dao = db.getUserDAOs()
        dao.getAllUsers() /*<<<< force open the database in case no code runs */

        if (DATABASE_VERSION == 1) {
            dao.insert(User("Fred", "passwordFred")) /* Original */
            dao.insert(User("Mary", "passwordMary")) /* Original */
        }
        /* commented out for V1 as mobile not a field in the User */
        if (DATABASE_VERSION == 2) {
            dao.insert(User("Jane","passwordJane","1234567890"))
            dao.insert(User("John","passwordJohn","0987654321"))
            dao.insert(User("Pat","passwordPat"))
        }
    }
}

当应用程序运行时,应用程序检查现在显示:-

可以看出:

  • Fred和Mary具有未提供移动电话的可识别指示符,即,它是xxxxxxxxxx
  • Alice已作为迁移的一部分添加(这并不是通常会包括在内,只是为了显示已执行迁移)
  • Jane和John已添加了他们提供的移动电话号码
  • 根据字段默认值,Pat已添加默认值(由于mobile不可为空,因此无法应用数据库默认值)
    • 最终测试**

剩下的概念验证是当新用户安装应用程序时,即全新安装。在此场景中,对于演示,将仅插入三个V2用户(Jane、John和Pat):

    • 显然,插页反映了应用程序用户可能执行的操作**

相关问题