¿Cómo usar @Transactional con Spring Data?

82

Acabo de empezar a trabajar en un proyecto Spring-data, Hibernate, MySQL, JPA. Cambié a Spring-Data para no tener que preocuparme por crear consultas a mano.

Noté que @Transactionalno se requiere el uso de cuando usa Spring-Data ya que también probé mis consultas sin la anotación.

¿Existe una razón específica por la que debería / no debería usar la @Transactionalanotación?

Trabajos:

@Transactional
public List listStudentsBySchool(long id) {
    return repository.findByClasses_School_Id(id);
}

También funciona:

public List listStudentsBySchool(long id) {
    return repository.findByClasses_School_Id(id);
}

¡Gracias por adelantado!

Byron Voorbach
fuente

Respuestas:

140

¿De qué se trata realmente tu pregunta? El uso de la @Repositoryanotación o @Transactional.

@Repositoryno es necesario en absoluto, ya que la interfaz que declara estará respaldada por un proxy que la infraestructura de Spring Data crea y activa la traducción de excepciones de todos modos. Entonces, el uso de esta anotación en una interfaz de repositorio de Spring Data no tiene ningún efecto en absoluto.

@Transactional- para el módulo JPA tenemos esta anotación en la clase de implementación que respalda el proxy ( SimpleJpaRepository). Esto se debe a dos razones: primero, la persistencia y eliminación de objetos requiere una transacción en JPA. Por lo tanto, debemos asegurarnos de que se esté ejecutando una transacción, lo que hacemos al anotar el método con @Transactional.

Los métodos de lectura como findAll()y findOne(…)están utilizando, @Transactional(readOnly = true)que no son estrictamente necesarios, pero desencadenan algunas optimizaciones en la infraestructura de transacciones (configurar FlushModeto MANUALpara permitir que los proveedores de persistencia puedan omitir las comprobaciones sucias al cerrar EntityManager). Más allá de eso, la bandera también se establece en la conexión JDBC, lo que provoca más optimizaciones en ese nivel.

Dependiendo de la base de datos que utilice, puede omitir bloqueos de tabla o incluso rechazar operaciones de escritura que podría activar accidentalmente. Por lo tanto, recomendamos usar también los @Transactional(readOnly = true)métodos de consulta que puede lograr fácilmente agregando esa anotación a la interfaz de su repositorio. Asegúrese de agregar un simple @Transactionala los métodos de manipulación que podría haber declarado o redecorado en esa interfaz.

Oliver Drotbohm
fuente
8
En resumen: ¿debería usar @Transactional para agregar / editar / eliminar consultas y @Transaction (readOnly = true) en consultas seleccionadas en todos mis métodos DAO?
Byron Voorbach
20
Exactamente. La forma más sencilla de hacerlo es utilizando @Transactional(readOnly = true)en la interfaz (ya que generalmente contiene principalmente métodos de búsqueda) y anular esta configuración para cada método de consulta de modificación con un archivo @Transactional. De hecho, esa es la forma en que se hace SimpleJpaRepositoy.
Oliver Drotbohm
@Oliver, gracias por la explicación completa ... Pero mientras pasa por otro enlace [transaction-pit-falls] < ibm.com/developerworks/java/library/j-ts1/index.html#listing8 >. Dice " La conclusión es que cuando usa un marco basado en ORM, el indicador de solo lectura es bastante inútil y en la mayoría de los casos se ignora. Pero si aún insiste en usarlo, configure siempre el modo de propagación en SUPPORTS " . . Después de leer esto, no estoy seguro de si debería usar (readOnly = true) solo ... si siempre se usa con el modo de propagación como SOPORTES.
Anupam Gupta
8
Casi todo está mal en esta sección del artículo. Al indicar que no está escribiendo, el JDBC impulsado puede (mejorará) el rendimiento de las interacciones DB. También puede detectar y rechazar escrituras emitidas accidentalmente. Además de eso, Spring deshabilita el vaciado de JPA / Hibernate en modo de solo lectura, lo que puede afectar enormemente el rendimiento en caso de que lea gráficos de objetos grandes, ya que el proveedor no necesita realizar comprobaciones sucias en él. Sin embargo, es posible que la bandera no tenga un gran impacto en la transacción en sí, pero eso no es todo a considerar.
Oliver Drotbohm
Puedo dar fe de las mejoras de rendimiento en caso de gráficos de objetos grandes o casos de uso que cargan una gran cantidad de objetos administrados.
Shailendra
3

Creo que la pregunta es un poco más amplia y no se puede reducir en las anotaciones en la capa de acceso a datos. Necesitamos considerar la pila completa de la aplicación, las estrategias de transacción que queremos aplicar, etc. Hay un conjunto muy completo de artículos sobre este tema de Mark Richards en el sitio de IBM developerworks. Puede encontrar el primero aquí: https://developer.ibm.com/articles/j-ts1/

Atentamente

dgiffone
fuente
2

Deberías usar la @Repositoryanotación

Esto se debe a que @Repositoryse utiliza para traducir su excepción de SQL sin marcar a Spring Excpetion y la única excepción que debe tratar esDataAccessException

danny.lesnik
fuente
10
Esto es cierto en general cuando se usa Spring, pero dado que los repositorios de Spring Data ya están respaldados por un proxy de Spring, usar @Repository no hace ninguna diferencia.
Aleksander Blomskøld
0

También usamos la anotación @Transactional para bloquear el registro para que otro hilo / solicitud no cambie la lectura.

Zozo
fuente