PlatformTransactionManager는 인터페이스로 실제로 사용하는 구현 객체는DataSourceTransactionManager를 사용한다
별도로 재정의하지 않는다면 기본적인 DataSourceTransactionManager를 사용하게 되고 DataSourceTransactionManager는 DataSource Bean을 사용하게 된다
그럼 동적으로 DataSource를 변경하려면 어떻게 해야할까?
트랜잭션 수행시 동적으로 Datasource를 정의하기 위해서는 PlatformTransactionManager를 재정의해야 한다
@Bean(name = "transactionManager")
public PlatformTransactionManager transactionManager(@Qualifier("routingLazyDataSource") DataSource dataSource) {
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
transactionManager.setDataSource(dataSource);
return transactionManager;
}
재정의된 PlatformTransactionManager는 동적으로 DataSource를 할당할 수 있도록 LazyConnectionDataSourceProxy 객체를 사용한다
@Bean("routingLazyDataSource")
public DataSource routingLazyDataSource(DataSource dataSource) {
return new LazyConnectionDataSourceProxy(dataSource);
}
LazyConnectionDataSourceProxy에 정의된 dataSource는 AbstractRoutingDataSource를 상속받은 객체로 determineCurrentLookupKey를 오버라이드하게 되면 동적으로 할당된 dataSource 시점을 지정할 수 있다
public DataSource getMasterDataSource() {
DataSourceProperties dataSourceProperties = new DataSourceProperties();
dataSourceProperties.setDriverClassName("com.mysql.cj.jdbc.Driver");
dataSourceProperties.setUrl("jdbc:mysql://127.0.0.1:3306/temp");
dataSourceProperties.setUsername("root");
dataSourceProperties.setPassword("password");
return dataSourceProperties.initializeDataSourceBuilder().type(HikariDataSource.class).build();
}
private DataSource getSlaveDataSource() {
DataSourceProperties dataSourceProperties = new DataSourceProperties();
dataSourceProperties.setDriverClassName("com.mysql.cj.jdbc.Driver");
dataSourceProperties.setUrl("jdbc:mysql://127.0.0.1:3307/temp");
dataSourceProperties.setUsername("root");
dataSourceProperties.setPassword("password");
return dataSourceProperties.initializeDataSourceBuilder().type(HikariDataSource.class).build();
}
@Bean
public DataSource dataSource() {
Map<Object, Object> targetDataSources = new HashMap<>();
targetDataSources.put("master", getMasterDataSource());
targetDataSources.put("slave", getSlaveDataSource());
CustomRoutingDataSource dataSource = new CustomRoutingDataSource();
dataSource.setTargetDataSources(targetDataSources);
dataSource.setDefaultTargetDataSource(getMasterDataSource());
return dataSource;
}
AbstractRoutingDataSource는 targetDataSource를 결정할 수 있는 객체이다