Issue
Recently I've decided to start using LiveData
in my Room database by adding it to ado methods and then observing them in ViewModel
, then even though I updated DB version after making all the changes and made a migration, it throws this error on emulator launch
2022-07-03 15:35:17.723 4866-4891/com.example... E/SQLiteLog: (1) statement aborts at 1: [ROLLBACK;] cannot rollback - no transaction is active
2022-07-03 15:35:17.724 4866-4891/com.example... E/AndroidRuntime: FATAL EXCEPTION: arch_disk_io_0
Process: com.example..., PID: 4866
java.lang.RuntimeException: Exception while computing database live data.
at androidx.room.RoomTrackingLiveData$1.run(RoomTrackingLiveData.java:92)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:920)
Caused by: android.database.sqlite.SQLiteException: cannot rollback - no transaction is active (code 1 SQLITE_ERROR)
at android.database.sqlite.SQLiteConnection.nativeExecute(Native Method)
at android.database.sqlite.SQLiteConnection.execute(SQLiteConnection.java:709)
at android.database.sqlite.SQLiteSession.endTransactionUnchecked(SQLiteSession.java:441)
at android.database.sqlite.SQLiteSession.endTransaction(SQLiteSession.java:403)
at android.database.sqlite.SQLiteDatabase.endTransaction(SQLiteDatabase.java:589)
at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:422)
at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:316)
at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper$OpenHelper.getWritableSupportDatabase(FrameworkSQLiteOpenHelper.java:151)
at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper.getWritableDatabase(FrameworkSQLiteOpenHelper.java:112)
at androidx.room.RoomDatabase.inTransaction(RoomDatabase.java:706)
at androidx.room.RoomDatabase.assertNotSuspendingTransaction(RoomDatabase.java:483)
at androidx.room.RoomDatabase.query(RoomDatabase.java:526)
at androidx.room.util.DBUtil.query(DBUtil.java:86)
at com.example...data.database.NoteDao_Impl$16.call(NoteDao_Impl.java:723)
at com.example...data.database.NoteDao_Impl$16.call(NoteDao_Impl.java:720)
at androidx.room.RoomTrackingLiveData$1.run(RoomTrackingLiveData.java:90)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:920)
My dao code :
@Dao
interface NoteDao {
@Delete
fun deleteFolder(folder: Folder)
@Query("UPDATE Note SET isStarred = :state WHERE id = :id")
fun updateNoteChecked(id : Int, state : Boolean)
@Query("DELETE FROM Note WHERE id = :id")
fun deleteNoteById(id : Int)
@Query("SELECT * FROM Note WHERE id = :id")
fun getNoteById(id : Int) : Note
@Query("SELECT title FROM Folder WHERE id = :id")
fun getFolderTitleById(id : Int) : String
@Query("SELECT * FROM folder WHERE id = :id")
fun getFolderById(id : Int) : Folder
@Query("UPDATE Folder SET title = :title WHERE id = :id")
fun updateFolderTitle(id : Int, title : String)
@Query("SELECT * FROM Folder WHERE id = :id")
fun getFolderWithNotesByFolderId(id : Int) : FolderWithNotes
@Query("SELECT * FROM Note WHERE folderId = :id ORDER BY isStarred")
fun getNotesByFolderId(id : Int) : LiveData<List<Note>>
@Query("SELECT * FROM note WHERE content LIKE :query ORDER BY isStarred")
fun searchAllNotes(query : String?) : LiveData<List<Note>>
@Query("SELECT * FROM note WHERE folderId = :id AND content LIKE :query ORDER BY isStarred" )
fun searchNotesByFolderId(query : String?, id : Int) : LiveData<List<Note>>
@Query("SELECT * FROM Note ORDER BY isStarred")
fun getAllNotes() : LiveData<List<Note>>
@Query("SELECT * FROM Folder WHERE id = :id")
fun getFolderWithNotes(id : Int) : List<FolderWithNotes>
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertFolder(folder : Folder)
@Query("SELECT * FROM Folder")
fun getAllFolders() : LiveData<List<Folder>>
@Query("UPDATE folder SET noteCount = noteCount + 1 WHERE id = :id")
fun updateOnInsertNote(id : Int)
@Query("UPDATE folder SET noteCount = noteCount - 1 WHERE id = :id")
fun updateOnDeleteNote(id : Int)
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertNote(note : Note)
@Delete
suspend fun deleteNote(note : Note)
}
Database class :
@Database(entities = [Note::class, Folder::class] , version = 11 )
abstract class NoteDatabase : RoomDatabase() {
abstract fun NoteDao() : NoteDao
}
Data base hilt provide method :
@Provides
@Singleton
fun provideNoteDatabase(app : Application) : NoteDatabase{
return Room.databaseBuilder(
app ,
NoteDatabase::class.java,
"notes",
).fallbackToDestructiveMigration()
.addCallback(DatabaseCallback())
.build()
}
Solution
As per my comment, I suspect that the issue is within the callback (DatabaseCallback) and probably in the overidden onOpen
method.
The reasoning is that the trace shows:-
- that you have issued a query as per
at androidx.room.RoomDatabase.query(RoomDatabase.java:526)
- that this successfully opens the database as per
at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:316)
-and then appears to end a transaction (without committing the transaction). As Room is proven, then the most likely issue is that an attempt is being made to end a transaction when no transaction has been started and thus, due to the lack of the commit, there is nowhere/nothing to rollback to.
Answered By - MikeT
Answer Checked By - Marie Seifert (JavaFixing Admin)