¿Debería colocar el @Transactional
en las DAO
clases y / o sus métodos o es mejor anotar las clases de Servicio que están llamando usando los objetos DAO? ¿O tiene sentido anotar ambas "capas"?
¿Debería colocar el @Transactional
en las DAO
clases y / o sus métodos o es mejor anotar las clases de Servicio que están llamando usando los objetos DAO? ¿O tiene sentido anotar ambas "capas"?
Respuestas:
Creo que las transacciones pertenecen a la capa de Servicio. Es el que sabe 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.
En general, estoy de acuerdo con los otros que afirman 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)
mientras tanto, también comencé a agregar a mi capa DAO (y otras capas que no pueden iniciar transacciones pero requieren las existentes) porque es mucho más fácil detectar errores en los que ha 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 donde verifico todos los beans (postprocesador de bean) para esta anotación y fallo si hay una @Transactional
anotación con propagación que no sea obligatoria en un bean que no pertenece a la capa de servicios. De esta manera, me aseguro de no iniciar transacciones en la capa incorrecta.
@Transactional
la clase de implementación del Servicio, y debería poner @Transactional(propagation = MANDATORY)
la implementación de la clase DAO (repositorio)?
Las anotaciones transaccionales se deben colocar alrededor de todas las operaciones que son inseparables.
Por ejemplo, su llamada es "cambiar contraseña". Que consiste en dos operaciones
Entonces, en lo anterior, si la auditoría falla, ¿también debería fallar el cambio de contraseña? Si es así, la transacción debería ser alrededor de 1 y 2 (por lo tanto, en la capa de servicio). Si el correo electrónico falla (probablemente debería tener algún tipo de protección contra fallas para que no falle), ¿debería revertir el cambio de contraseña y la auditoría?
Este es el tipo de preguntas que debe hacerse al decidir dónde colocar el @Transactional
.
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 la primavera es hacia el diseño impulsado por dominio (DDD). Spring Roo ejemplifica muy bien la tendencia. La idea es hacer que los POJO de objetos de dominio sean mucho más ricos de lo que son en las arquitecturas típicas de Spring (generalmente son anémicas ), y en particular poner semántica de transacciones y persistencia en los objetos de dominio. En los casos en que todo lo que se necesita son operaciones CRUD simples, los controladores web operan directamente en los POJO de objetos de dominio (funcionan como entidades en este contexto), y no hay nivel de servicio. En los casos en que se necesite algún tipo de coordinación entre los objetos de dominio, puede tener un identificador de servicio que, con@Transaction
según la tradición Puede establecer la propagación de transacciones en los objetos de dominio en algo así REQUIRED
para que los objetos de 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 utiliza las definiciones entre tipos de AspectJ para separar la semántica de la entidad (transacciones y persistencia) de las cosas del objeto de dominio (básicamente campos y métodos comerciales).
El caso normal sería anotar en un nivel de capa de servicio, pero esto realmente depende de sus requisitos.
Anotar en una capa de servicio dará como resultado transacciones más largas que anotar en el nivel DAO. Dependiendo del nivel de aislamiento de la transacción que puede solucionar problemas, ya que las transacciones concurrentes no verán los cambios de cada uno, por ejemplo. LECTURA REPETIBLE.
Anotar en los DAO mantendrá 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 (revertible).
No tiene sentido anotar ambas capas si el modo de propagación está configurado por defecto.
Coloco el @Transactional
en la @Service
capa y establezco rollbackFor
cualquier excepción y readOnly
para optimizar aún más la transacción.
De manera predeterminada @Transactional
, solo buscará RuntimeException
(Excepciones no marcadas), al establecer la reversión en Exception.class
(Excepciones marcadas), se revertirá para cualquier excepción.
@Transactional(readOnly = false, rollbackFor = Exception.class)
Consulte Excepciones marcadas frente a no marcadas .
¿O tiene sentido anotar ambas "capas"? - no tiene sentido anotar tanto la capa de servicio como la capa de dao - si uno quiere asegurarse de que el método DAO siempre se llame (propague) desde una capa de servicio con propagación "obligatoria" en DAO. Esto proporcionaría alguna restricción para que los métodos DAO se invoquen desde la capa UI (o controladores). Además, cuando la unidad prueba la capa DAO en particular, tener DAO anotado también garantizará que se pruebe la funcionalidad transaccional.
propagation=Propagation.REQUIRES_NEW
. De lo contrario, para la mayoría de los casos, incluida la propagación = obligatoria, el DAO solo participará en la transacción existente iniciada por la capa de servicio.
Además, Spring solo recomienda usar la anotación en clases concretas y no en interfaces.
http://static.springsource.org/spring/docs/2.0.x/reference/transaction.html
Para transacciones en el nivel de base de datos
principalmente lo usé @Transactional
en DAO solo a nivel de método, por lo que la configuración puede ser específicamente para un método / uso predeterminado (requerido)
El método de DAO que obtiene la búsqueda de datos (seleccione ...): no es necesario,
@Transactional
esto puede generar algunos gastos generales debido al interceptor de transacciones / y al proxy AOP que también deben ejecutarse.
Los métodos de DAO que insertan / actualizan obtendrán @Transactional
muy buen blog sobre transctional
Para el nivel de aplicación:
estoy usando la lógica transaccional para negocios, me gustaría poder deshacerme en caso de error inesperado
@Transactional(rollbackFor={MyApplicationException.class})
public void myMethod(){
try {
//service logic here
} catch(Throwable e) {
log.error(e)
throw new MyApplicationException(..);
}
}
Transactional
enJava
Por lo general, uno debe colocar una transacción en la capa de servicio.
Pero como se dijo anteriormente, 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 "guardar / actualizar / eliminar / ... modificación" en un objeto tiene el potencial de modificar varias filas en varias tablas (debido a la cascada a través del gráfico de objetos), de Por supuesto, también debería haber gestión de transacciones en este método DAO específico.
@Transactional
Las anotaciones deben colocarse alrededor de todas las operaciones que son inseparables. El uso de la @Transactional
propagación de transacciones se maneja automáticamente. En este caso, si el método actual llama a otro método, ese método tendrá la opción de unirse a la transacción en curso.
Entonces tomemos ejemplo:
Tenemos 2 modelos de ie Country
y City
. El mapeo relacional Country
y el City
modelo es como uno Country
puede tener múltiples ciudades, por lo que el mapeo es como,
@OneToMany(fetch = FetchType.LAZY, mappedBy="country")
private Set<City> cities;
Aquí el país se asignó a varias ciudades con ir a buscarlas Lazily
. Así que aquí viene el papel de @Transactinal
cuando recuperamos el objeto Country de la base de datos, entonces obtendremos todos los datos del objeto Country 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 desde el objeto de 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 utilizamos @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();
}
Entonces, básicamente, el @Transactional
Servicio puede realizar múltiples llamadas en una sola transacción sin cerrar la conexión con el punto final.
@Transactional
realmente es
El @Transactional
debe utilizar en la capa de servicio, ya que contiene la lógica de negocio. La capa DAO generalmente solo tiene operaciones CRUD de bases de datos.
// the service class that we want to make transactional
@Transactional
public class DefaultFooService implements FooService {
Foo getFoo(String fooName);
Foo getFoo(String fooName, String barName);
void insertFoo(Foo foo);
void updateFoo(Foo foo);
}
Documento de Spring: https://docs.spring.io/spring/docs/4.2.x/spring-framework-reference/html/transaction.html
La capa de servicio es el mejor lugar para agregar @Transactional
anotaciones, ya que la mayoría de la lógica de negocios 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, una DB se comprometerá y otra se revertirá.
Por lo tanto, mi recomendación es usar esta anotación sabiamente y usarla solo en la capa de Servicio.
En primer lugar vamos a definir todos de donde tenemos que el uso de transacciones ?
Creo que la respuesta correcta es: cuando necesitamos asegurarnos de que la secuencia de acciones se completará como una operación atómica o no se realizarán cambios, incluso si una de las acciones falla.
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 única unidad lógica de trabajo. Si es así, entonces dicho método debe marcarse como Transaccional . Por supuesto, no todos los métodos requieren tal limitación, por lo que no necesita marcar 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 una imagen completa, debe conocer los niveles de aislamiento de las transacciones. Saber eso podría ayudarlo a evitar usar @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 su manipulación de la base de datos en la capa intermedia y escribir la lógica empresarial en la capa de servicio. La capa intermedia interactuará con sus capas DAO.
Esto lo ayudará en muchas situaciones, como ObjectOptimisticLockingFailureException : esta excepción se produce solo después de que finaliza su transacción. Por lo tanto, no puede atraparlo en la capa intermedia, pero puede atraparlo en su capa de servicio ahora. Esto no sería posible si tiene @Transactional en la capa de Servicio. Aunque puede atrapar 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 hacerlo en el 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 se enviará incluso si su transacción falla.
Por lo tanto, tener una capa media de @Transaction ayudará a que su código sea mejor y más fácil de manejar. De lo contrario, si usa 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. Supongamos una situación en la que tiene N número de operaciones DAO en un método de servicio. Si su primera operación DAO falló, es posible que se pasen otras y usted terminará en un estado de base de datos inconsistente. La capa de servicio de anotación puede salvarlo de tales situaciones.
Prefiero usar @Transactional
en la capa de servicios a nivel de método.