Room and Conflict Resolution
For @Insert
and @Update
methods in your @Dao
, you can have onConflict
properties in the annotations that stipulate what should happen if the insert or update results in a violation of a few types of constraints:
- A unique index, including a duplicate primary key
- A
NULL
value being put into aNOT NULL
column - A
CHECK
constraint (which Room does not support presently)
Room gives you five OnConflictStrategy
enum values to choose from for your onConflict
property. Each of those OnConflictStrategy
values maps to an equivalent SQLite keyword, and each of those strategies results is different behavior in SQLite.
Value | Meaning |
---|---|
OnConflictStrategy.ABORT |
Cancel this statement but preserve prior results in the transaction and keeps the transaction alive |
OnConflictStrategy.FAIL |
Like ABORT , but accepts prior changes by this specific statement (e.g., if we fail on the 50th row to be updated, keep the changes to the preceding 49) |
OnConflictStrategy.IGNORE |
Like FAIL , but continues processing this statement (e.g., if we fail on the 50th row out of 100, keep the changes to the other 99) |
OnConflictStrategy.REPLACE |
For uniqueness violations, deletes other rows that would cause the violation before executing this statement |
OnConflictStrategy.ROLLBACK |
Rolls back the current transaction |
However, they may not wind up with different behavior in Room, due to the way that Room works with SQLite.
In this chapter, we will examine those five options and see what SQLite does and what the resulting effects are in a Room-based app. As you will see, while there are five official options, fewer are practical.
Abort
@Insert(onConflict = OnConflictStrategy.ABORT)
@Update(onConflict = OnConflictStrategy.ABORT)
What SQLite Does
This strategy maps to INSERT OR ABORT
or UPDATE OR ABORT
statements. If a constraint violation would occur from this statement, the statement is skipped. SQLiteDatabase
throws a SQLiteConstraintException
. However, if you have started a transaction, that transaction remains open, so further statements in the transaction can be executed.
Effects in Room
An individual @Insert
or @Update
method that uses OnConflictStrategy.ABORT
will throw a SQLiteConstraintException
if there is a constraint violation. In isolation, this fits with what you might expect.
The problem comes with @Transaction
.
Every method that Room generates in response to your @Dao
-annotated methods has the same basic structure:
@Override
public void whatever(SomeEntity... entities) {
__db.beginTransaction();
try {
// the real work for whatever whatever() does
__db.setTransactionSuccessful();
} finally {
__db.endTransaction();
}
}
This includes @Transaction
-annotated methods, which just wrap that template around a call to your real method:
@Override
public void whatever(SomeEntity... entities) {
__db.beginTransaction();
try {
super.whatever(entities);
__db.setTransactionSuccessful();
} finally {
__db.endTransaction();
}
}
If anything in your @Transaction
method throws an exception, of any kind, the entire transaction gets rolled back, courtesy of the try
/finally
structure.
So, even though ABORT
is supposed to keep the transaction open, Room rolls back the transaction, so that your @Transaction
is atomic.
Prev Table of Contents Next
This book is licensed under the Creative Commons Attribution-ShareAlike 4.0 International license.