java spring - ¿A dónde pertenece la anotación @Transactional?




example rollback (17)

¿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"?


Answers

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).


@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.


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.


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.


@Transactional utiliza en la capa de servicio que se llama mediante la capa de controlador ( @Controller ) y la llamada de la capa de servicio a la capa DAO ( @Repository ), es decir, la operación relacionada con la base de datos.


Creo que las transacciones pertenecen a la capa de servicio. Es el que conoce sobre unidades de trabajo y casos de uso. Es la respuesta correcta si tiene varios DAO inyectados en un Servicio que necesitan trabajar juntos en una sola transacción.


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 capa de servicio es el mejor lugar para agregar @Transactional anotaciones @Transactional ya que la mayoría de la lógica empresarial presente aquí contiene un comportamiento de caso de uso de nivel de detalle.

Supongamos que lo agregamos a DAO y desde el servicio estamos llamando a 2 clases DAO, una fallida y otra exitosa, en este caso si @Transactional no está en servicio, se comprometerá una base de datos y la otra se revertirá.

Por lo tanto, mi recomendación es usar sabiamente esta anotación y usarla solo en la capa de Servicio.

Proyecto Github- java-algos


En primer lugar vamos a definir dónde tenemos que usar la transacción ?

Creo que la respuesta correcta es: cuando necesitamos asegurarnos de que la secuencia de acciones se complete como una sola operación atómica o no se realicen cambios, incluso si falla una de las acciones.

Es una práctica bien conocida poner la lógica de negocios en los servicios. Por lo tanto, los métodos de servicio pueden contener diferentes acciones que deben realizarse como una sola unidad lógica de trabajo. Si es así, entonces dicho método debe estar marcado como Transaccional . Por supuesto, no todos los métodos requieren dicha limitación, por lo que no es necesario que marque todo el servicio como transaccional .

Y aún más: no olvide tener en cuenta que @Transactional , obviamente, puede reducir el rendimiento del método. Para ver la imagen completa, debe conocer los niveles de aislamiento de las transacciones. Saber eso podría ayudarlo a evitar el uso de @Transactional donde no es necesariamente necesario.


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.



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.


¡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!


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


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 .


¿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.


Como complemento de la answer @djechlin (¡buena respuesta, por cierto!), Esta función de llamada también se puede usar como código ficticio para mantener un punto de interrupción en un IDE cuando desee detenerse en una iteración específica o una llamada recursiva en particular, por ejemplo:

isUserAGoat() podría usarse en lugar de una declaración de variable ficticia que se mostrará en el IDE como una advertencia y, en un caso particular de Eclipse, obstruirá la marca del punto de interrupción, lo que dificultará su habilitación / inhabilitación. Si el método se utiliza como una convención, todas las invocaciones podrían filtrarse posteriormente mediante algún script (¿quizás durante la fase de confirmación?).

Los usuarios de Google son usuarios intensos de Eclipse (proporcionan varios de sus proyectos como complementos de Eclipse: Android SDK, GAE, etc.), por lo que la respuesta de @djechlin y esta respuesta complementaria tienen mucho sentido (al menos para mí).





java spring annotations transactions dao