“Android 로봇은 Google에서 제작하여 공유한 저작물을 복제하거나 수정한 것으로 Creative Commons 3.0 저작자 표시 라이선스의 약관에 따라 사용되었습니다.”
개인 프로젝트 앱에 새로운 쿼리를 추가하려는데 의도대로 동작이 안되는 거 같아서
Logging을 해보려는데 @Query 는 @Delete나 @Update처럼 성공 결과를 반환하지 않으니 Logging을 하기가 애매했다.
그래서 방법을 찾아보았는데 Query 처리에 대한 콜백을 제공하는 것을 발견,
여기서 Log를 찍어보기로 했다.
이 방법은 Room 2.4.0 버전 이상부터 지원합니다.
우선 사용방법은 아래와 같이 setQueryCallback()이라는 메소드를
Room 객체를 생성할때 Builder에 추가해준다.
Room.databaseBuilder(
context,
MyDatabase::class.java,
"MyDB.db"
)
.addMigrations(*MIGRATIONS)
.setQueryCallback({ query, args ->
Log.d("query: $query\t\nargs: $args")
}, Executors.newSingleThreadExecutor())
.build()
/**
* Sets a [QueryCallback] to be invoked when queries are executed.
*
* The callback is invoked whenever a query is executed, note that adding this callback
* has a small cost and should be avoided in production builds unless needed.
*
* A use case for providing a callback is to allow logging executed queries. When the
* callback implementation logs then it is recommended to use an immediate executor.
*
* @param queryCallback The query callback.
* @param executor The executor on which the query callback will be invoked.
* @return This builder instance.
*/
@Suppress("MissingGetterMatchingBuilder")
open fun setQueryCallback(
queryCallback: QueryCallback,
executor: Executor
) = apply {
this.queryCallback = queryCallback
this.queryCallbackExecutor = executor
}
매개변수를 보면 QueryCallback, Executor를 요구하는데
핵심은 QueryCallback 다.
/**
* Callback interface for when SQLite queries are executed.
*
* Can be set using [RoomDatabase.Builder.setQueryCallback].
*/
fun interface QueryCallback {
/**
* Called when a SQL query is executed.
*
* @param sqlQuery The SQLite query statement.
* @param bindArgs Arguments of the query if available, empty list otherwise.
*/
fun onQuery(sqlQuery: String, bindArgs: List<Any?>)
}
SQLite가 쿼리를 실행할때 이 인터페이스를 통해 콜백을 전달받는다.
그럼 그 콜백에서 Log를 작성해주면..
쿼리가 실행될때마다 아래와 같이 Log가 출력된다.
23:37:50.733 D [DHModule.kt::onQuery] query: BEGIN DEFERRED TRANSACTION
args: []
23:37:50.734 D [DHModule.kt::onQuery] query: INSERT OR IGNORE INTO room_table_modification_log VALUES(1, 0)
args: []
23:37:50.734 D [DHModule.kt::onQuery] query: CREATE TEMP TRIGGER IF NOT EXISTS `room_table_modification_trigger_charactersentity_UPDATE` AFTER UPDATE ON `charactersentity` BEGIN UPDATE room_table_modification_log SET invalidated = 1 WHERE table_id = 1 AND invalidated = 0; END
args: []
23:37:50.735 D [DHModule.kt::onQuery] query: CREATE TEMP TRIGGER IF NOT EXISTS `room_table_modification_trigger_charactersentity_DELETE` AFTER DELETE ON `charactersentity` BEGIN UPDATE room_table_modification_log SET invalidated = 1 WHERE table_id = 1 AND invalidated = 0; END
args: []
23:37:50.736 D [DHModule.kt::onQuery] query: CREATE TEMP TRIGGER IF NOT EXISTS `room_table_modification_trigger_charactersentity_INSERT` AFTER INSERT ON `charactersentity` BEGIN UPDATE room_table_modification_log SET invalidated = 1 WHERE table_id = 1 AND invalidated = 0; END
args: []
23:37:50.737 D [DHModule.kt::onQuery] query: TRANSACTION SUCCESSFUL
args: []
23:37:50.737 D [DHModule.kt::onQuery] query: END TRANSACTION
args: []
23:37:50.738 D [DHModule.kt::onQuery] query: SELECT * FROM CharactersEntity
args: []
보다시피 트랜젝션의 결과도 알려주기 때문에
내가 만든 쿼리와 파라미터, 작동 여부도 모두 확인해 볼 수 있다.
만약 개발중인 앱에 DB 사용량이 많다면 이 방법을 사용해서
Logging을 하는 것도 괜찮을 것으로 생각된다.
개인적으로 공부했던 것을 바탕으로 작성하다보니
잘못된 정보가 있을수도 있습니다.
인지하게 되면 추후 수정하겠습니다.
피드백은 언제나 환영합니다.
읽어주셔서 감사합니다.