先以一个例子看下效果
@Dao
interface Dao {
//----增
// 添加一条数据
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(data :Data)
// 添加一个集合
@Insert(onConflict = REPLACE)
@JvmSuppressWildcards
fun insert(list : MutableList)
//----删
// 根据条件删除指定条目
@Query("DELETE FROM Data WHERE data_key = :key")
fun delete(key: String)
// 删除所有数据
@Query("DELETE FROM Data")
fun deleteAll()
//----改
//----查
// 根据word正序排序
@Query("SELECT * FROM Data ORDER BY word DESC")
fun getAllWords() : LiveData>
// 只查一条数据
@Query("SELECT * FROM Data WHERE type = :_type")
fun getConfigByAdType(_type : Int) : Data?
// 根据last_time大小正序查询limit条数据
@Query("SELECT * FROM SearchRecord ORDER BY last_time DESC LIMIT :limitNum")
fun getWords(limitNum : Int) : LiveData>
// 复杂查询 -查询最后limit条数据按正序排列
@Query("SELECT * FROM (SELECT * FROM NewsFeedData WHERE type = :type AND channelName = :channelName ORDER BY id DESC LIMIT :limit) 'linshi' ORDER BY id")
fun loadData(type : Int,channelName : String,limit: Int) : List
}
room 中在插入数据方法上加@Insert(onConflict = OnConflictStrategy.REPLACE)的作用是什么?
@Insert(onConflict = OnConflictStrategy.REPLACE)
注解用于在插入数据时指定冲突策略。如果数据库中已经存在相同的记录(即主键或唯一约束列值相同),那么根据指定的冲突策略来处理这个冲突。
在这里,指定的冲突策略是 OnConflictStrategy.REPLACE
,表示如果存在冲突,则用新数据替换旧数据。换句话说,如果插入的记录已经存在于数据库中,那么将使用新记录替换旧记录,而不是插入一个新记录。
使用该注解的好处是可以避免插入重复的数据,并且可以确保每次插入的数据都是最新的。这在一些需要频繁更新数据的场景中非常有用,例如缓存最新的数据。
以下是一个示例:
@Entity
data class User(
@PrimaryKey val id: Int,
val name: String,
val age: Int
)
@Dao
interface UserDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insert(user: User)
}
val userDao = appDatabase.userDao()
// 新增一个用户
val user = User(1, "John Doe", 30)
userDao.insert(user)
// 更新用户信息
val updatedUser = User(1, "John Smith", 35)
userDao.insert(updatedUser) // 会用新数据更新旧数据
在这个例子中,UserDao 的 insert 方法上使用了 @Insert(onConflict = OnConflictStrategy.REPLACE)
注解。如果插入的用户已经存在于数据库中,则会用新的用户数据更新旧的用户数据。
总的来说,
@Insert(onConflict = OnConflictStrategy.REPLACE)
注解提供了一种简单的方法来避免插入重复的数据,并保证每次插入的数据都是最新的。
除了onConflict = OnConflictStrategy.REPLACE,room还提供什么策略?
除了 OnConflictStrategy.REPLACE,Room 还提供了其他几种冲突策略,以便根据具体的需求选择合适的策略。以下是 Room 支持的冲突策略列表:
OnConflictStrategy.ABORT
:默认的冲突策略。如果发生冲突,则会抛出 SQLiteConstraintException 异常。
OnConflictStrategy.FAIL
:与 ABORT 类似,但是不会抛出异常。而是会直接导致事务回滚。
OnConflictStrategy.IGNORE
:如果插入的记录已经存在,则不执行插入操作,也不会抛出异常。这种策略通常用于忽略一些无关紧要的数据冲突。
OnConflictStrategy.REPLACE
:如果存在冲突,则用新数据替换旧数据。
OnConflictStrategy.ROLLBACK
:与 FAIL 类似,但是会撤销所有未提交的事务。
使用这些冲突策略时,需要根据具体的业务场景和数据要求来选择合适的策略。例如,如果要避免插入重复的数据,可以使用 OnConflictStrategy.IGNORE
或 OnConflictStrategy.REPLACE
;如果需要确保每次插入的数据都是最新的,可以使用 OnConflictStrategy.REPLACE
;如果需要保证数据完整性,可以使用 OnConflictStrategy.FAIL
或 OnConflictStrategy.ROLLBACK
。
以下是一个示例,演示了 Room 使用不同的冲突策略的方法:
@Entity
data class User(
@PrimaryKey val id: Int,
val name: String,
val age: Int
)
@Dao
interface UserDao {
@Insert(onConflict = OnConflictStrategy.IGNORE)
suspend fun insert(user: User)
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertOrUpdate(user: User)
@Insert(onConflict = OnConflictStrategy.FAIL)
suspend fun insertOrFail(user: User)
@Insert(onConflict = OnConflictStrategy.ROLLBACK)
suspend fun insertWithRollback(user: User)
}
val userDao = appDatabase.userDao()
// 新增一个用户
val user = User(1, "John Doe", 30)
userDao.insert(user)
// 忽略重复数据
val sameUser = User(1, "John Doe", 30)
userDao.insert(sameUser) // 不会执行插入操作
// 使用新数据更新旧数据
val updatedUser = User(1, "John Smith", 35)
userDao.insertOrUpdate(updatedUser) // 会用新数据更新旧数据
// 插入重复数据会抛出异常
userDao.insertOrFail(user) // 抛出异常
// 插入重复数据会回滚所有事务
userDao.insertWithRollback(user) // 会回滚所有事务
什么是插入重复数据会回滚所有事务?
在 Room 中,如果在执行 INSERT 操作时遇到了冲突,并且采用了 OnConflictStrategy.ROLLBACK
策略,那么 Room 会撤销所有未提交的事务,以保证数据的一致性和完整性。
事务是指一系列数据库操作,这些操作在执行过程中作为一个单一的操作单元,要么全部执行成功,要么全部撤销,以保证数据库的一致性和可靠性。在 Room 中,开发者可以通过 @Transaction
注解来定义事务方法,以确保这些操作在一个事务中执行。如果在一个事务中执行了多个操作,其中任意一个操作失败,那么这个事务就会失败,并且所有的操作都会被撤销,以回到事务开始的状态。
当使用OnConflictStrategy.ROLLBACK
策略时,如果在执行 INSERT 操作时发生了冲突,那么这个操作所在的事务以及所有未提交的事务都会被撤销。这样可以保证数据的完整性和一致性,避免数据出现不一致的情况。
下面是一个示例,演示了使用 OnConflictStrategy.ROLLBACK
策略时 Room 如何回滚事务:
@Dao
interface UserDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insert(users: List)
@Insert(onConflict = OnConflictStrategy.ROLLBACK)
suspend fun insertWithRollback(user: User)
}
val userDao = appDatabase.userDao()
// 定义一个事务方法
@Transaction
suspend fun insertUsers(users: List) {
userDao.insert(users)
// 向数据库中插入一个重复数据,会导致事务回滚
userDao.insertWithRollback(users.first())
}
// 向数据库中插入多条数据
val users = listOf(
User(1, "John Doe", 30),
User(2, "Jane Smith", 25),
User(3, "Tom Brown", 40)
)
insertUsers(users) // 会回滚所有事务
在这个例子中,我们在一个事务方法 insertUsers
中插入了多条数据,并且在其中插入了一个重复数据。由于使用了 OnConflictStrategy.ROLLBACK
策略,因此当插入重复数据时,整个事务以及所有未提交的事务都会被回滚,因此数据库中不会留下任何数据。