java - jpatransactionmanager - @EnableTransactionManagement anotación con 2 gestores de transacciones
transactionmanager spring 4 (6)
Estoy usando la anotación @Configuration
para la configuración de spring en lugar de un archivo xml. Estoy configurando 2 fuentes de datos con diferentes sesiones de fábrica y diferentes gestores de transacciones. Estoy atascado con un problema aquí para la anotación @EnableTransactionManagement
. Leí en su documentación que,
@EnableTransactionManagement
es más flexible; volverá a una búsqueda por tipo para cualquier beanPlatformTransactionManager
en el contenedor. Por lo tanto, el nombre puede ser "txManager", "transactionManager" o "tm": simplemente no importa.
Esto significa que cualquiera sea el nombre que le dé al método, siempre buscará el método que devuelve el objeto PlatformTransactionManager
mientras tengo 2 gestores de transacciones. Ahora el problema es que cuando pruebo esta clase, me da un error:
org.springframework.beans.factory.NoSuchBeanDefinitionException
: No seorg.springframework.beans.factory.NoSuchBeanDefinitionException
ningún bean único de tipo [org.springframework.transaction.PlatformTransactionManager
]: se espera un solo bean pero se encuentra 2
Incluso intenté tener 2 clases de configuración diferentes pero en vano. En la configuración xml, este no fue el caso. Registré mis dos gestores de transacciones con dos etiquetas <tx:annotation-driven transaction-manager="" />
y funcionó bien. Pero no puedo hacer lo mismo aquí con anotaciones.
¿Qué debo hacer si quiero configurar 2 fuentes de datos con 2 administradores de transacciones diferentes en la clase de configuración anotada Spring?
Algunas de las otras respuestas implican que el uso de dos administradores de transacciones está mal de alguna manera; sin embargo, la configuración XML de Spring permite usar múltiples administradores de transacciones como se indica en la documentación en línea (a continuación). Desafortunadamente, no parece haber una manera de hacer que la anotación @EnableTransactionManagement
funcione de manera similar. Como resultado, simplemente uso una anotación @ImportResource
para cargar un archivo XML que incluye la línea <tx:annotation-driven/>
. Esto le permite obtener una configuración de Java para la mayoría de las cosas pero aún así hacer uso de @Transactional
con un calificador de Transaction Manager opcional.
http://docs.spring.io/spring/docs/3.1.x/spring-framework-reference/html/transaction.html
La mayoría de las aplicaciones Spring solo necesitan un solo administrador de transacciones, pero puede haber situaciones en las que desee tener múltiples administradores de transacciones independientes en una sola aplicación. El atributo de valor de la anotación
@Transactional
se puede usar para especificar opcionalmente la identidad delPlatformTransactionManager
que se usará. Puede ser el nombre del bean o el valor calificador del bean del administrador de transacciones. Por ejemplo, usando la notación de calificador, el siguiente código de Java
Desde el documento java
Para aquellos que deseen establecer una relación más directa entre
@EnableTransactionManagement
y el bean del administrador de transacciones exacto que se utilizará, la interfaz de devolución de llamadaTransactionManagementConfigurer
puede implementarse. Observe la cláusula de implementos y el método anotado@Override
Override-abajo:
Su clase @Configuration
necesita implementar la interfaz TransactionManagementConfigurer
: implemente el annotationDrivenTransactionManager
que devolverá la referencia al transactionManager
que debe usarse.
En caso de que alguien se encuentre con este problema, encontré una solución:
@Configuration
@EnableTransactionManagement
@DependsOn("myTxManager")
@ImportResource("classpath:applicationContext.xml")
public class AppConfig implements TransactionManagementConfigurer {
@Autowired
private PlatformTransactionManager myTxManager;
...
@Override
public PlatformTransactionManager annotationDrivenTransactionManager() {
return this.myTxManager;
}
De esta manera, puede usar un txManager específico definido en una configuración xml.
En caso de que desee definir el txManager usado en el nivel de servicio, deberá eliminar la anotación @EnableTransactionManagement
de la clase @Configuration
y especificar el txManager en las anotaciones @Transactional
, por ejemplo
@Service
@Transactional(value="myTxManager", readOnly = true)
public class MyServiceImpl implements MyService { ... }
En su clase de configuración, use la anotación @EnableTransactionManagement
.
Defina un administrador de transacciones en esta clase como:
@Bean(name="txName")
public HibernateTransactionManager txName() throws IOException{
HibernateTransactionManager txName= new HibernateTransactionManager();
txName.setSessionFactory(...);
txName.setDataSource(...);
return txName;
}
A continuación, en su clase / método que ejecuta trabajos transaccionales, anote de la siguiente manera:
@Transactional("txName")
o
@Transactional(value = "txName")
Así es como uniría a un administrador de transacciones calificado con el nombre a donde lo necesites. Ahora puede tener tantos administradores de transacciones como desee y utilizarlos en consecuencia donde lo necesite.
No estoy seguro de por qué está utilizando dos TransactionManagers. Podría considerar usar el mismo TransactionManager para múltiples fuentes de datos a través de AbstractRoutingDataSource. Consulte
http://blog.springsource.org/2007/01/23/dynamic-datasource-routing/
para una muestra de su uso.
Trate de usar TransactionalManager encadenado
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.transaction.ChainedTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
@Configuration
public class ChainedDBConfig {
@Bean("chainedTransactionManager")
public PlatformTransactionManager transactionManager(
@Qualifier("database1TransactionManager") final PlatformTransactionManager db1PlatformTransactionManager,
@Qualifier("database2TransactionManager") final PlatformTransactionManager db2PlatformTransactionManager) {
return new ChainedTransactionManager(db1PlatformTransactionManager, db2PlatformTransactionManager);
}
}
Y coloque la siguiente anotación en su clase de servicio:
@Transactional(transactionManager = "chainedTransactionManager")
public class AggregateMessagesJobIntegrationTest {
...
}
También puedes usarlo dentro de las pruebas de integración:
@RunWith(SpringRunner.class)
@Transactional(transactionManager = "chainedRawAndAggregatedTransactionManager")
@Rollback
public class ExampleIntegrationTest extends AbstractIntegrationTest {
....
}
y hará una reversión para ambos administradores de transacciones DB.