Can ExecSQL поддерживает несколько операторов sql

#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. Лучше, хотя все еще есть некоторые крайние случаи, такие как выброс коммита