java - example - timeout transaction spring




¿A dónde pertenece la anotación @Transactional? (13)

¿Debería colocar @Transactional en las clases DAO y / o sus métodos o es mejor anotar las clases de servicio que están usando los objetos DAO? ¿O tiene sentido anotar ambas "capas"?


¡Es mejor tenerlo en la capa de servicio! ¡Esto se explica claramente en uno de los artículos que encontré ayer! Aquí está el enlace que puedes revisar!



El caso normal sería anotar en un nivel de capa de servicio, pero esto realmente depende de sus requisitos.

La anotación en una capa de servicio resultará en transacciones más largas que en la anotación en el nivel DAO. Dependiendo del nivel de aislamiento de la transacción que pueda usar, ya que las transacciones concurrentes no se verán los cambios de los demás, por ejemplo. READATABLE LEER.

Las anotaciones en los DAO mantendrán las transacciones lo más cortas posible, con el inconveniente de que la funcionalidad que su capa de servicio está exponiendo no se realizará en una sola transacción (reversible).

No tiene sentido anotar ambas capas si el modo de propagación está configurado por defecto.


En general, estoy de acuerdo con los demás que indican que las transacciones generalmente se inician en el nivel de servicio (dependiendo de la granularidad que requiera, por supuesto).

Sin embargo, @Transactional(propagation = Propagation.MANDATORY) también comencé a agregar @Transactional(propagation = Propagation.MANDATORY) a mi capa DAO (y otras capas a las que no se les permite iniciar transacciones pero que requieren de las existentes) porque es mucho más fácil detectar errores donde usted tiene olvidado iniciar una transacción en la persona que llama (por ejemplo, el servicio). Si su DAO está anotado con propagación obligatoria, obtendrá una excepción que indica que no hay una transacción activa cuando se invoca el método.

También tengo una prueba de integración en la que verifico todos los beans (postprocesador de bean) para esta anotación y fallo si hay una anotación @Transactional con propagación diferente a la obligatoria en un bean que no pertenece a la capa de servicios. De esta manera me aseguro de que no iniciemos transacciones en la capa incorrecta.


Es mejor mantener @Transactional en una capa intermedia separada entre DAO y Service Layer. Dado que la reversión es muy importante, puede colocar toda la manipulación de su base de datos en la capa intermedia y escribir la lógica empresarial en la capa de servicio. La capa intermedia interactuará con tus capas DAO.

Esto lo ayudará en muchas situaciones como ObjectOptimisticLockingFailureException : esta excepción se produce solo después de que finalice su transacción. Por lo tanto, no puede capturarlo en la capa intermedia, pero puede capturarlo en su capa de servicio ahora. Esto no sería posible si tiene @Transactional en la capa de Servicio. Aunque puede atrapar en el Controlador, el Controlador debe estar lo más limpio posible.

Si está enviando correo o SMS en un hilo separado después de completar todas las opciones de guardar, eliminar y actualizar, puede hacer esto en servicio después de que se complete la transacción en su capa intermedia. Nuevamente, si menciona @Transactional en la capa de servicio, su correo irá incluso si su transacción falla.

Por lo tanto, tener una capa intermedia de @Transaction ayudará a que su código sea mejor y más fácil de manejar. De lo contrario, si utiliza en la capa DAO, es posible que no pueda deshacer todas las operaciones. Si usa en la capa de Servicio, puede que tenga que usar AOP (Programación Orientada a Aspectos) en ciertos casos.


Idealmente, la capa de servicio (administrador) representa la lógica de su negocio y, por lo tanto, debe anotarse con @Transactional La capa de servicio puede llamar a diferentes DAO para realizar operaciones de base de datos. Asumamos situaciones en las que tiene un número N de operaciones DAO en un método de servicio. Si su primera operación DAO falló, es posible que se sigan pasando otros y terminará en un estado de base de datos inconsistente. La capa de servicio de anotación puede salvarlo de tales situaciones.


La respuesta correcta para las arquitecturas tradicionales de Spring es colocar la semántica transaccional en las clases de servicio, por las razones que otros ya han descrito.

Una tendencia emergente en Spring es hacia el diseño controlado por dominio (DDD). Spring Roo ejemplifica muy bien la tendencia. La idea es hacer que el objeto de dominio POJO sea mucho richer que en las arquitecturas típicas de Spring (generalmente son anemic ) y, en particular, poner semántica de transacción y persistencia en los objetos de dominio. En los casos en los que todo lo que se necesita son simples operaciones CRUD, los controladores web operan directamente en los objetos de dominio (POJO) del objeto (funcionan como entidades en este contexto) y no hay nivel de servicio. En los casos en que se necesita algún tipo de coordinación entre los objetos del dominio, puede tener un bean de servicio que se encargue de eso, con @Transaction según la tradición. Puede establecer la propagación de transacciones en los objetos del dominio en algo así como REQUIRED para que los objetos del dominio utilicen cualquier transacción existente, como las transacciones que se iniciaron en el bean de servicio.

Técnicamente, esta técnica hace uso de AspectJ y <context:spring-configured /> . Roo usa las definiciones de los tipos de AspectJ para separar la semántica de la entidad (transacciones y persistencia) de las cosas del objeto del dominio (básicamente, campos y métodos comerciales).


Las anotaciones transaccionales se deben colocar alrededor de todas las operaciones que son inseparables.

Por ejemplo, su llamada es "cambiar contraseña". Que consta de dos operaciones.

  1. Cambia la contraseña.
  2. Auditar el cambio.
  3. Envíe un correo electrónico al cliente que la contraseña ha cambiado.

Entonces, en lo anterior, si la auditoría falla, ¿también debería fallar el cambio de contraseña? Si es así, entonces la transacción debe ser de alrededor de 1 y 2 (por lo tanto, en la capa de servicio). Si el correo electrónico falla (probablemente debería haber algún tipo de protección contra fallas en este para que no falle), ¿debería revertir la contraseña de cambio y la auditoría?

Este es el tipo de preguntas que debe hacer al decidir dónde colocar @Transactional .


Por lo general, uno debe poner una transacción en la capa de servicio.

Pero como se dijo antes, la atomicidad de una operación es lo que nos dice dónde es necesaria una anotación. Por lo tanto, si utiliza marcos como Hibernate, donde una sola operación de "guardar / actualizar / eliminar / ... modificación" en un objeto tiene la posibilidad de modificar varias filas en varias tablas (debido a la cascada a través del gráfico de objetos), de Por supuesto, también debe haber administración de transacciones en este método DAO específico.


Prefiero usar @Transactional en la capa de servicios en el nivel de método.


@Transactional anotaciones de @Transactional deben colocar alrededor de todas las operaciones que son inseparables. El uso de la propagación de transacciones @Transactional se maneja automáticamente. En este caso, si otro método es llamado por el método actual, entonces ese método tendrá la opción de unirse a la transacción en curso.

Así que vamos a tomar el ejemplo:

Tenemos 2 modelos, es decir, Country y City . El modelo de mapeo relacional de Country y City es como un Country puede tener múltiples ciudades, por lo que el mapeo es:

@OneToMany(fetch = FetchType.LAZY, mappedBy="country")
private Set<City> cities;

Aquí el país mapeado a varias ciudades con ir a buscarlas Lazily . Así que aquí viene el rol de @Transactinal cuando recuperamos el objeto País de la base de datos, luego obtendremos todos los datos del objeto País, pero no obtendremos el Conjunto de ciudades porque estamos buscando ciudades LAZILY .

//Without @Transactional
public Country getCountry(){
   Country country = countryRepository.getCountry();
   //After getting Country Object connection between countryRepository and database is Closed 
}

Cuando deseamos acceder al conjunto de ciudades del objeto país, obtendremos valores nulos en ese conjunto porque el objeto del conjunto creado solo este conjunto no se inicializa con los datos para obtener los valores del conjunto que usamos @Transactional , es decir,

//with @Transactional
@Transactional
public Country getCountry(){
   Country country = countryRepository.getCountry();
   //below when we initialize cities using object country so that directly communicate with database and retrieve all cities from database this happens just because of @Transactinal
   Object object = country.getCities().size();   
}

Básicamente, @Transactional is Service puede hacer varias llamadas en una sola transacción sin cerrar la conexión con el punto final.


@Transactional el @Transactional en la capa @Service y configuro rollbackFor cualquier excepción y readOnly para optimizar aún más la transacción.

Por defecto, @Transactional solo buscará RuntimeException (Excepciones no verificadas), al establecer rollback en Exception.class (Excepciones marcadas) se revertirá para cualquier excepción.

@Transactional(readOnly = false, rollbackFor = Exception.class)

Ver Excepciones marcadas y no verificadas .


¿O tiene sentido anotar ambas "capas"? - ¿No tiene sentido anotar tanto la capa de servicio como la capa dao? - si uno quiere asegurarse de que el método DAO siempre sea llamado (propagado) desde una capa de servicio con propagación "obligatoria" en DAO. Esto proporcionaría alguna restricción para que los métodos DAO no sean llamados desde la capa UI (o controladores). Además, cuando la unidad de prueba de la capa DAO en particular, tener una anotación DAO también asegurará que se pruebe la funcionalidad transaccional.





dao