Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android Room database transactions

With the new Room Database in Android, I have a requirement where there are two sequential operations that needs to be made:

removeRows(ids);
insertRows(ids);

If I run this, I see (on examining the db) that there are some rows missing - I assume they are being deleted after inserting. viz. the first operation is running in parallel to the second.

If I use a transaction block, such as this, then it's all fine - the first operation seems to complete before doing the second:

roomDb.beginTransaction();
removeRows(ids);
roomDb.endTransaction();

insertRows(ids);

It's also fine if I give a sleep in-between instead:

removeRows(ids);
Thread.sleep(500);

insertRows(ids);

There doesn't seem to be much documentation for Room, and was wondering if I should use the transaction block like the above when I have sequential operations to be done, or is there any better way of doing it.

EDIT: After @CommonsWare pointed out, @Query are asynchronous, while @Insert and @Delete are synchronous. In view of this, how would I get a query which deletes rows to be async:

@Query("DELETE from table WHERE id IN(:ids)")
int removeRows(List<Long> ids);

According to the build output I get Deletion methods must either return void or return int (the number of deleted rows), if I try to wrap the return type in a Flowable.

like image 838
Rajath Avatar asked Jun 23 '17 02:06

Rajath


People also ask

What is transaction in room database?

android.arch.persistence.room.Transaction. Marks a method in a Dao class as a transaction method. When used on a non-abstract method of an abstract Dao class, the derived implementation of the method will execute the super method in a database transaction. All the parameters and return types are preserved.

Is room database deprecated?

This field is deprecated.

What is the room database in Android?

What is Room? Room is a persistence library that provides an abstraction layer over the SQLite database to allow a more robust database. With the help of room, we can easily create the database and perform CRUD operations very easily.

Is room in Android an ORM?

Is Android Room an ORM? Room isn't an ORM; instead, it is a whole library that allows us to create and manipulate SQLite databases more easily. By using annotations, we can define our databases, tables, and operations.


4 Answers

As pointed out on documentation for Transaction, you can do following:

 @Dao
 public abstract class ProductDao {
    @Insert
    public abstract void insert(Product product);

    @Delete
    public abstract void delete(Product product);

    @Transaction
    public void insertAndDeleteInTransaction(Product newProduct, Product oldProduct) {
         // Anything inside this method runs in a single transaction.
         insert(newProduct);
         delete(oldProduct);
     }
 }
 
like image 134
guness Avatar answered Oct 19 '22 03:10

guness


As @CommonsWare pointed out, @Query are asynchronous , while @Insert , @Delete , @Update are synchronous.

If you want to execute multiple queries in single transaction , Room also provides a method for that as mentioned below.

roomDB.runInTransaction(new Runnable() {
        @Override
        public void run() {
            removeRows(ids);
            insertRows(ids);
        }
    });

I hope this will solve your problem.

like image 43
Pinakin Kansara Avatar answered Oct 19 '22 03:10

Pinakin Kansara


For Room transactions in Kotlin you can use:

  • Interface with implemented method, like:
@Dao 
interface Dao {

    @Insert 
    fun insert(item: Item)

    @Delete 
    fun delete(item: Item)

    @Transaction
    fun replace(oldItem: Item, newItem: Item){
        delete(oldItem)
        insert(newItem)
    }

}
  • Or use open function, like:
@Dao 
abstract class Dao {

    @Insert 
    abstract fun insert(item: Item)

    @Delete 
    abstract fun delete(item: Item)

    @Transaction
    open fun replace(oldItem: Item, newItem: Item){
        delete(oldItem)
        insert(newItem)
    }

}

You'll get error: Method annotated with @Transaction must not be private, final, or abstract. without open modifier.

like image 30
Daniel Avatar answered Oct 19 '22 03:10

Daniel


I believe when we are using DAO interfaces, still we can perform transaction using default interface methods. We need to add the annotation @JvmDefault and @Transaction and we can perform any operation inside that, which belong to single transaction.

@Dao
interface TestDao {
    @Insert
    fun insert(dataObj: DataType)

    @Update
    fun update(dataObj: DataType): Completable

    @Delete
    fun delete(dataObj: DataType): Completable

    @Query("DELETE FROM $TABLE_NAME")
    fun deleteAllData()

    @Query("SELECT * FROM $TABLE_NAME ORDER BY id DESC")
    fun getAllData(): Single<List<DataType>>

    @JvmDefault
    @Transaction
    fun singleTransaction(dataList: List<DataType>) {
        deleteAllData()
        dataList.forEach {
            insert(it)
        }
    }
}
like image 45
AK Ali Avatar answered Oct 19 '22 02:10

AK Ali