¿Por qué necesito Transacción en Hibernate para operaciones de solo lectura?

107

¿Por qué necesito Transacción en Hibernate para operaciones de solo lectura?

¿La siguiente transacción bloquea la base de datos?

Código de ejemplo para obtener de DB:

Transaction tx = HibernateUtil.getCurrentSession().beginTransaction(); // why begin transaction?
//readonly operation here

tx.commit() // why tx.commit? I don't want to write anything

¿Puedo usar en session.close() lugar de tx.commit()?

user93796
fuente
9
La propia base de datos requiere la transacción. Puede leer sobre el modo de confirmación automática aquí: community.jboss.org/wiki/…
Bhesh Gurung
@BheshGurung supongo que solo requerimos la transcación para la operación de escritura
user93796
4
¿Leíste la parte del enlace "Desmentir los mitos de confirmación automática"?
Bhesh Gurung

Respuestas:

131

Es posible que tenga motivos para marcar las transacciones como de solo lectura.

  1. Las transacciones de lectura pueden parecer realmente extrañas y, en este caso, a menudo la gente no marca los métodos para las transacciones. Pero JDBC creará una transacción de todos modos, es solo que funcionará autocommit=truesi no se estableció explícitamente una opción diferente.
  2. Pero no hay garantía de que su método no escriba en la base de datos. Si marca el método como @Transactional(readonly=true), Spring establecerá la transacción JDBC en un modo de solo lectura, por lo que dictará si es realmente posible escribir en la base de datos en el alcance de esta transacción. Si su arquitectura es engorrosa y algunos miembros del equipo pueden optar por colocar una consulta de modificación donde no se espera, este indicador le indicará el lugar problemático.
  3. Las bases de datos también pueden optimizar las transacciones de solo lectura, pero esto, por supuesto, es específico de la base de datos. Por ejemplo, MySQL agregó soporte para esto solo en InnoDB a partir de la versión 5.6.4.
  4. Si no está usando JDBC directamente, sino un ORM, eso podría ser problemático. Por ejemplo, la comunidad de Hibernate dice que trabajar fuera de la transacción puede causar un comportamiento impredecible. Esto se debe a que Hibernate abrirá la transacción, pero no la cerrará por sí solo, por lo que la conexión se devolverá al Connection Pool con la transacción no confirmada. ¿Qué pasa entonces? JDBC guarda silencio, por lo tanto, esto es específico de la implementación (MySQL revierte la transacción, Oracle afair la confirma). Esto también se puede configurar en el nivel del grupo de conexiones (por ejemplo, C3P0 le ofrece esta opción, la reversión de forma predeterminada).
  5. Otra cosa cuando se trata de Hibernate, Spring establece el FlushMode en MANUAL en el caso de transacciones de solo lectura, lo que conduce a otras optimizaciones como la no necesidad de verificaciones sucias.
  6. Es posible que desee anular o establecer explícitamente el nivel de aislamiento de la transacción. Esto también afecta las transacciones de lectura, ya que desea o no leer cambios no confirmados, estar expuesto a lecturas fantasmas, etc.

En resumen, puede ir en ambos sentidos, pero debe comprender las consecuencias.

Stanislav Bashkyrtsev
fuente
Gracias por responder Estoy usando hibernate (native hibernate, no jpa). Pero hibernate me obliga a iniciar una transcación antes de realizar cualquier operación de base de datos. Si no inicio una, arroja un error que dice que no hay tracscation activo. ¿Puedo marcar la transcación como solo lectura , si es así, ¿cómo?
user93796
El indicador de solo lectura está configurado para la conexión, no para la transacción en sí, y no puede acceder a él a través de Hibernate así como así. Debe utilizar el soporte de Spring Transaction y utilizar anotaciones o una configuración transaccional basada en XML. Al hacer eso, Spring toma la propiedad de la administración de conexiones y transacciones en lugar de Hibernate.
Stanislav Bashkyrtsev
1
¡Muy bien explicado! Otro artículo de Mark Richards explica bastante bien las trampas del indicador de solo lectura en la anotación transaccional: ibm.com/developerworks/java/library/j-ts1/index.html .
Mahesh
48

Todas las declaraciones de la base de datos se ejecutan dentro del contexto de una transacción física, incluso cuando no declaramos explícitamente los límites de la transacción (BEGIN / COMMIT / ROLLBACK).

Si no declara los límites de la transacción explícitamente, entonces cada declaración deberá ejecutarse en una transacción separada ( autocommitmodo). Esto incluso puede llevar a abrir y cerrar una conexión por declaración a menos que su entorno pueda lidiar con el enlace de conexión por subproceso.

Declarar un servicio como @Transactionalle dará una conexión durante toda la duración de la transacción, y todas las declaraciones utilizarán esa única conexión de aislamiento. Esto es mucho mejor que no utilizar transacciones explícitas en primer lugar.

En aplicaciones grandes, es posible que tenga muchas solicitudes simultáneas, y la reducción de la tasa de solicitudes de adquisición de conexión de base de datos definitivamente mejorará el rendimiento general de su aplicación.

JPA no impone transacciones en operaciones de lectura. Solo las escrituras terminan lanzando una excepción de transacción requerida en caso de que olvide iniciar un contexto transaccional. Sin embargo, siempre es mejor declarar los límites de las transacciones incluso para las transacciones de solo lectura (en Spring le @Transactionalpermite marcar transacciones de solo lectura, lo que tiene un gran beneficio de rendimiento).

Vlad Mihalcea
fuente
1
"... entonces cada declaración deberá ejecutarse en una transacción separada". ¿El contenedor no procesa por lotes automáticamente?
Arash
El procesamiento por lotes es para modificaciones, no para leer datos. Y aún así, el procesamiento por lotes de JDBC no está habilitado de forma predeterminada cuando se usa JPA e Hibernate.
Vlad Mihalcea
1
Gracias Vlad. Leí algunos de sus artículos. Son realmente útiles.
Arash
Este stackoverflow.com/q/34797480/179850 parece contradecir un poco su afirmación de que las transacciones de solo lectura tienen un gran beneficio de rendimiento. Al menos, no parece ser el caso en el contexto de hibernación.
nimai
No, no es así. Se trata de configurar solo lectura, mientras que el mío consiste en evitar la confirmación automática.
Vlad Mihalcea
17

De hecho, las transacciones bloquean la base de datos (los buenos motores de base de datos manejan bloqueos simultáneos de manera sensata) y son útiles con el uso de solo lectura para garantizar que ninguna otra transacción agregue datos que hagan que su vista sea inconsistente. Siempre desea una transacción (aunque a veces es razonable ajustar el nivel de aislamiento, es mejor no hacerlo para empezar); si nunca escribe en la base de datos durante su transacción, tanto la confirmación como la reversión de la transacción resultan ser iguales (y muy baratas).

Ahora, si tiene suerte y sus consultas contra la base de datos son tales que el ORM siempre las asigna a consultas SQL únicas, puede salirse con la suya sin transacciones explícitas , confiando en el comportamiento de confirmación automática incorporado en la base de datos, pero los ORM son sistemas relativamente complejos. por lo tanto, no es seguro confiar en tal comportamiento a menos que trabaje mucho más para verificar lo que realmente hace la implementación. Escribir los límites de transacción explícitos es mucho más fácil de hacer bien (especialmente si puede hacerlo con AOP o alguna técnica similar impulsada por ORM; desde Java 7 en adelante, también se podría usar try-with-resources, supongo).

Becarios Donal
fuente
14

No importa si solo lee o no, la base de datos aún debe realizar un seguimiento de su conjunto de resultados, porque otros clientes de la base de datos pueden querer escribir datos que cambiarían su conjunto de resultados.

He visto programas defectuosos para matar sistemas de bases de datos enormes, porque solo leen datos, pero nunca se comprometen, lo que obliga a que el registro de transacciones crezca, porque la base de datos no puede liberar los datos de la transacción antes de COMMIT o ROLLBACK, incluso si el cliente no hizo nada por horas.

Ingo
fuente