#android #sqlite
#Android #sqlite
Вопрос:
Может ли ExecSQL поддерживать несколько операторов или я должен выполнять отдельные команды. Мой вариант использования относится к контексту транзакций.
fun update(id: Long, roles: List<Role>): Int? {
val values = (roles.map { role -> "($id, ${role.id})" }).joinToString(",")
val sql = "BEGIN TRANSACTION; DELETE FROM user_role WHERE user_id = $id;" (if (values.count() > 0) "INSERT INTO user_role(user_id, role_id) VALUES$values; " else "") "COMMIT;"
connection.writableDatabase.execSQL(sql)
return connection.readableDatabase.rawQuery("SELECT changes()", null).use { cursor ->
return@use cursor.count
}
}
Альтернативный подход, который работает, заключается в следующем.
fun update(id: Long, roles: List<Role>): Int? {
val values = (roles.map { role -> "($id, ${role.id})" }).joinToString(",")
connection.writableDatabase.execSQL("BEGIN TRANSACTION;")
connection.writableDatabase.execSQL("DELETE FROM user_role WHERE user_id = $id;")
if (values.count() > 0) connection.writableDatabase.execSQL("INSERT INTO user_role(user_id, role_id) VALUES$values")
connection.writableDatabase.execSQL("COMMIT")
return connection.readableDatabase.rawQuery("SELECT changes()", null).use { cursor ->
return@use cursor.count
}
}
ПОПРОБУЙТЕ УЛОВИТЬ ПОДХОД
fun update(id: Long, roles: List<Role>): Int? {
try {
connection.writableDatabase.execSQL("BEGIN TRANSACTION;")
connection.writableDatabase.execSQL("DELETE FROM user_role WHERE user_id = $id;")
val values = (roles.map { role -> "($id, ${role.id})" }).joinToString(",")
if (values.count() > 0) connection.writableDatabase.execSQL("INSERT INTO user_role(user_id, role_id) VALUES$values")
connection.writableDatabase.execSQL("COMMIT")
} catch(exception: Exception) {
connection.writableDatabase.execSQL("ROLLBACK")
return null
}
return connection.readableDatabase.rawQuery("SELECT changes()", null).use { cursor ->
return@use cursor.count
}
}
Ответ №1:
Нет.
execSQL()
выполняет только отдельные операторы. Все, что после первого ;
, игнорируется.
хорошо, известно ли, что ExecSQL выдает ошибки, на всякий случай, если возникнет проблема, чтобы я мог выполнить откат, должен ли я включить ее в блок try catch?
Да, он может генерировать исключения. Канонический шаблон для транзакций — это что-то вроде (Java, но идея та же в Kotlin):
db.beginTransaction();
try {
// db operations that can throw and should be executed atomically
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
Идея заключается в том, что endTransaction()
это откат, если транзакция не будет установлена как успешная в конце блока try.
Комментарии:
1. хорошо, известно ли, что ExecSQL выдает ошибки, на всякий случай, если есть проблема, чтобы я мог выполнить откат, должен ли я включить ее в блок try catch?
2. да, я согласен с этим
beginTransaction
, поскольку я использовал его раньше, но с использованием необработанного sql в моем примере, согласны ли вы с моим подходом??3. В вашем подходе есть проблема с вызовом блока finally
commit
без транзакции, если вы уже откатили транзакцию в блоке catch.4. да, у вас есть точка, отредактировано, это нормально?
5. Лучше, хотя все еще есть некоторые крайние случаи, такие как выброс коммита