Soy nuevo en Spring Transaction. Algo que encontré realmente extraño, probablemente lo entendí bien.
Quería tener un nivel de método transaccional y tengo un método de llamada dentro de la misma clase y parece que no le gusta eso, tiene que ser llamado desde la clase separada. No entiendo cómo es eso posible.
Si alguien tiene una idea de cómo resolver este problema, se lo agradecería enormemente. Me gustaría usar la misma clase para llamar al método transaccional anotado.
Aquí está el código:
public class UserService {
@Transactional
public boolean addUser(String userName, String password) {
try {
// call DAO layer and adds to database.
} catch (Throwable e) {
TransactionAspectSupport.currentTransactionStatus()
.setRollbackOnly();
}
}
public boolean addUsers(List<User> users) {
for (User user : users) {
addUser(user.getUserName, user.getPassword);
}
}
}
java
spring
aspectj
spring-aop
Miguel
fuente
fuente
TransactionTemplate
enfoque: stackoverflow.com/a/52989925/355438Respuestas:
Es una limitación de Spring AOP (objetos dinámicos y cglib ).
Si configura Spring para usar AspectJ para manejar las transacciones, su código funcionará.
La alternativa más simple y probablemente la mejor es refactorizar su código. Por ejemplo, una clase que maneja usuarios y otra que procesa a cada usuario. Entonces funcionará el manejo de transacciones predeterminado con Spring AOP.
Consejos de configuración para manejar transacciones con AspectJ
Para permitir que Spring use AspectJ para transacciones, debe establecer el modo en AspectJ:
Si está utilizando Spring con una versión anterior a la 3.0, también debe agregar esto a su configuración de Spring:
fuente
El problema aquí es que los proxies AOP de Spring no extienden, sino que envuelven su instancia de servicio para interceptar llamadas. Esto tiene el efecto de que cualquier llamada a "this" desde dentro de su instancia de servicio se invoca directamente en esa instancia y no puede ser interceptada por el proxy de envoltura (el proxy ni siquiera es consciente de dicha llamada). Ya se menciona una solución. Otro ingenioso sería simplemente hacer que Spring inyecte una instancia del servicio en el servicio mismo y llamar a su método en la instancia inyectada, que será el proxy que maneja sus transacciones. Pero tenga en cuenta que esto también puede tener efectos secundarios negativos, si su bean de servicio no es un singleton:
fuente
UserService
tiene alcance singleton? ¿Y si es el mismo objeto?Con Spring 4 es posible conectarse automáticamente
fuente
A partir de Java 8 hay otra posibilidad, que prefiero por las razones que se indican a continuación:
Este enfoque tiene las siguientes ventajas:
1) Puede aplicarse a métodos privados . Por lo tanto, no tiene que romper la encapsulación haciendo público un método solo para satisfacer las limitaciones de Spring.
2) Se puede llamar al mismo método dentro de una propagación de transacción diferente y es el llamador quien debe elegir el adecuado. Compare estas 2 líneas:
3) Es explícito, por lo tanto más legible.
fuente
TransactionHandler
como una subclase, y la subclase llama a estos dos métodos en laTransactionHandler
superclase, ¿podré seguir obteniendo los beneficios@Transactional
previstos?Esta es mi solución para la autoinvocación :
fuente
Puede conectar automáticamente BeanFactory dentro de la misma clase y hacer una
getBean(YourClazz.class)
Proxificará automáticamente su clase y tendrá en cuenta su @Transactional u otra anotación aop.
fuente
El problema está relacionado con la forma en que el resorte carga las clases y los proxies. No funcionará, hasta que escriba su método / transacción interno en otra clase o vaya a otra clase y luego vuelva a su clase y luego escriba el método de transcación anidado interno.
En resumen, los proxies de primavera no permiten los escenarios a los que se enfrenta. tienes que escribir el segundo método de transacción en otra clase
fuente
Esto es lo que hago para proyectos pequeños con un uso marginal de llamadas a métodos dentro de la misma clase. Se recomienda encarecidamente la documentación en código, ya que puede parecer extraño para los colegas. Pero funciona con singleton , es fácil de probar, simple, rápido de lograr y me ahorra la instrumentación AspectJ completa. Sin embargo, para un uso más intenso, recomendaría la solución AspectJ como se describe en la respuesta de Espens.
fuente