SQLiteDatabase transacción anidada y solución alternativa

Editado:
Sí, SQLite no admite transacciones anidadas, pero los documentos declaran que SQLiteDatabase hace.
Situación
Tengo un método que contiene la transacción y necesito llamar a este método de otra transacción.
Además, ambas transacciones funcionan en el mismo conjunto de registros, pero actualizan diferentes columnas.
Problema
Parece que los resultados de mis transacciones externas son cancelados por uno interno, aún ambos están marcados como limpios por setTransactionSuccessful () y terminados por endTransaction () – He comprobado esto.
Preguntas
– ¿Alguna idea de por qué esto puede suceder?
– ¿Hay una manera recomendada de realizar tales transacciones?

Puedes anidar transacciones con la API Android sqlite, con advertencias :

Las transacciones pueden anidarse. Cuando se termina la transacción externa todo el trabajo realizado en esa transacción y todas las transacciones anidadas se comprometerán o se revertirán. Los cambios se revertirán si se termina cualquier transacción sin estar marcada como limpia (llamando a setTransactionSuccessful). De lo contrario, se comprometerán.

Otro enfoque que he visto utilizado con sqlite en general es pasar en un parámetro booleano isInTransaction que indica el método llamado si debe manejar las transacciones por su cuenta, o para permitir que el llamador manejar las transacciones.

"Transacciones anidadas de Android" no utilizan SQLites anidados transacciones / savepoint de apoyo.

Más bien, una transacción anidada de Android suprime la manifestación de una transacción de SQLite. La transacción anidada no se puede revertir por sí misma, porque no existe aparte de la transacción externa. Esto se puede ver aquí con el mTransactionStack == null guard.

La única manera de apoyar realmente las transacciones anidadas, que soporta SQLite, pero no con BEGIN / COMMIT, es utilizar manualmente los comandos SAVEPOINT / RELEASE. Por supuesto, el diseño del código para no confiar en esto eliminará la gestión manual adicional que esto requiere.

(Probablemente movería todo el trabajo de transacción fuera de las operaciones individuales reales, dejando la gestión al llamador de alto nivel, esto funciona bastante bien para un patrón de UoW, pero no siempre puede ser aplicable).

Por ahora terminé con el diseño simétrico del método (similar a la sugerencia del laalto) que proporciona el trabajo correcto. Es una solución que explícitamente "convierte" transacciones anidadas en una sola.
Ahora puedo llamarlos por separado o uno de otro (sin efectos secundarios que todavía no entiendo).
Aquí está:

  public void method1() { SQLiteDatabase db = dbhelper.getWritableDatabase(); boolean doAsTransaction = !db.inTransaction(); if (doAsTransaction) db.beginTransaction(); try { // ... if (doAsTransaction) db.setTransactionSuccessful(); } catch (Exception e) { // ... } finally { // ... if (doAsTransaction) db.endTransaction(); } } public void method2() { SQLiteDatabase db = dbhelper.getWritableDatabase(); boolean doAsTransaction = !db.inTransaction(); if (doAsTransaction) db.beginTransaction(); try { // ... method1(); if (doAsTransaction) db.setTransactionSuccessful(); } catch (Exception e) { // ... } finally { // ... if (doAsTransaction) db.endTransaction(); } } 

Puede realizar transacciones anidadas utilizando raw SQL para savepoints en execSQL() de esta manera:

 db.execSql("SAVEPOINT test"); // declare savepoint // ... do some operations db.execSql(";ROLLBACK TO test"); // rollback db.execSql("RELEASE test"); // save changes 

Semicolon delante de ROLLBACK se requiere, porque sin él el marco de la base de datos de Android tratará de llamar a endTransaction() . Ver código de los métodos android.database.sqlite.SQLiteSession#executeSpecial y android.database.sqlite.SQLiteSession#execute para más detalles.

  • ¿Está bien actualizar fragmentos en lugar de crear nuevas instancias?
  • Android - cuándo llamar a db.setTransactionSuccessful ()?
  • Borrar backstack y reemplazar fragmento actual con un fragmento de nivel superior
  • Fragmento no se muestra cuando el método add () se llama
  • Android: niveles de aislamiento de transacciones SQLite (ORMLite)
  • ¿Debo usar siempre transacciones en android sqlite?
  • Transacción de la base de datos Android
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.