Android Room中如何为实体字段配置唯一约束?
问题原因
你配置的联合唯一索引失效,核心问题是把自增主键id放进了唯一索引字段列表里:
id字段设置了autoGenerate = true,每次插入新数据都会自动生成全局不重复的值- 联合唯一索引的判定规则是所有索引字段的值完全一致,才会判定为重复、拦截插入
- 只要每条数据的
id不一样,哪怕audio_id重复,(id, audio_id)的组合也永远不会重复,约束自然完全不生效
正确实现方式
根据实际业务需求选对应方案即可:
方案1:要求audio_id全局唯一
如果业务规则是整张表里不允许出现重复的audio_id,直接给audio_id单独配置唯一索引即可,修改@Entity注解配置:
@Entity( tableName = "playlist_members", indices = [Index(value = ["audio_id"], unique = true)] ) data class Members( @PrimaryKey(autoGenerate = true) @ColumnInfo(name = "id") val id: Int?, var title: String, var artist: String, var album: String, @ColumnInfo(name = "audio_id") val audioId: Int, val albumId: String )
也可以直接在audioId字段上加@Unique注解,效果和上面的单字段唯一索引完全一致:
@Entity(tableName = "playlist_members") data class Members( @PrimaryKey(autoGenerate = true) @ColumnInfo(name = "id") val id: Int?, var title: String, var artist: String, var album: String, @ColumnInfo(name = "audio_id") @Unique val audioId: Int, val albumId: String )
方案2:要求指定组合下audio_id唯一
如果业务规则是「同一个维度下audio_id不允许重复,不同维度可以重复」(比如同一个歌单下不能重复添加同一首歌、不同歌单可以加同一首),就把对应的业务维度字段和audio_id配成联合唯一索引,注意不要把自增主键id放进去。举个例子,如果表中有playlistId字段标记所属歌单,联合唯一索引写法如下:
@Entity( tableName = "playlist_members", indices = [Index(value = ["playlist_id", "audio_id"], unique = true)] )
注意事项
如果应用已经在设备上创建过这个数据库表,修改索引配置后不会自动生效:
- 调试阶段可以直接卸载应用重装,让Room重新创建表结构
- 正式环境必须升级数据库版本,编写对应的
Migration逻辑执行SQL创建新的唯一索引,否则会出现数据库版本不匹配的崩溃
内容的提问来源于stack exchange,提问作者KamDroid
相关产品推荐
相关产品推荐

