Room如何验证数据完整性?数据库版本/哈希值存储在哪里?

6

我的目标是使用Room的新createFromAsset API从应用程序的assets中加载预加载的数据库。 但是,我注意到如果我的预加载数据库没有room_master_table中由Room生成的id和标识哈希,那么会抛出“IllegalStateException:Room无法验证数据完整性。”异常。

我尝试使用由Room生成的精确db文件作为预加载的db进行复制,这样可以工作,但我不确定原因。看起来这些数据库版本/ id /哈希在某个地方保存,并且Room针对这些版本对其进行验证。但是我已经尝试删除本地db并卸载应用程序,但仍然遇到相同的异常。

我想知道Room如何在room_master_table中生成特定的id和哈希,以及它如何验证它们?


我建议您不要在预打包数据库中包含 room_master_table。当首次打开数据库时,Room 将验证模式并创建主表以及哈希(如果一切正常)。如果您包含了 room_master_table,那么它将看起来好像数据库已经被 Room 打开,此时 Room 将只比较哈希而不是进行更适当的模式检查。 - DanyBoricua
@DanyBoricua 这不正确。无论您是否提供 room_master_table,房间都会执行相同的操作。它始终独立于您是否提供 room_master_table 调用 SELECT identity_hash FROM room_master_table。然后将返回值(如果不存在则为 null)与编译的哈希进行比较。 - musooff
@musooff,根据Room的OpenHelper(其中检查了主表),这不是我的理解。请参见:https://android.googlesource.com/platform/frameworks/support/+/androidx-master-dev/room/runtime/src/main/java/androidx/room/RoomOpenHelper.java#141 - DanyBoricua
@DanyBoricua 正如您从源代码中指出的那样。它检查 room_master_table 中的 identity_has 是否存在,而不是检查 room_master_table 的存在。 - musooff
1个回答

6

Room Persistence Library为每个数据库版本生成唯一的identity_hash并存储在room_master_table中。

每次编译应用程序时,Room会生成反映当前数据库模式的mIdentityHash。每当您运行应用程序并首次调用数据库时,Room会将其与已存储在数据库中的mLegacyHash进行比较。因此,如果这两个哈希值不同,Room会抛出IlligalStateException异常。

所有这些过程都是通过注释处理库完成的,您需要将其添加到build.gradle文件中。

kapt "androidx.room:room-compiler:$room_version"
// annotationProcessing androidx.room:room-compiler:$room_version in case you use Java

您可以查看 Room源代码,进行详细验证。 查看RoomOpenHelper.java类,其中有checkIdentity()函数,在该函数中会检查identity_hash, 如果两个身份哈希值不匹配,则会抛出异常。
如果您想了解如何生成identity_key,请查看SchemaIdentityKey.kt 希望这对您有所帮助。

当您提到 mLegacyHash 时,它是否是当前在数据库中的 identity_hash - Dan
@Dan 是的。mLegacyHash是已经存在的,而mItendityHash是它使用新代码生成的。 - musooff

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接