package kr.pe.kwonnam.replicationdatasource.config;
import kr.pe.kwonnam.replicationdatasource.routingdatasource.ReplicationRoutingDataSource;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
/**
* {@link kr.pe.kwonnam.replicationdatasource.routingdatasource.ReplicationRoutingDataSource}와
* {@link org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy}를 사용한
* 리플리케이션 설정 예제.
* <p/>
* 동일한 테이블에 동일한 양의 데이터가 들어있지만 쓰기쪽은 write_x 읽기 쪽은 read_x 라는 형태의 name 컬럼 데이터를
* 가지도록 조작한 두 개의 데이터 소스를 생성한다.
* <p/>
* 실전 환경에서는 writeDataSource는 Master DB를, readDataSource는 Slave DB를 바라보는 커넥션 풀이어야 한다.
*/
@Configuration
public class WithRoutingDataSourceConfig {
@Bean(destroyMethod = "shutdown")
public DataSource writeDataSource() {
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder()
.setName("routingWriteDb")
.setType(EmbeddedDatabaseType.H2)
.setScriptEncoding("UTF-8")
.addScript("classpath:/writedb.sql");
return builder.build();
}
@Bean(destroyMethod = "shutdown")
public DataSource readDataSource() {
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder()
.setName("routingReadDb")
.setType(EmbeddedDatabaseType.H2)
.setScriptEncoding("UTF-8")
.addScript("classpath:/readdb.sql");
return builder.build();
}
/**
* {@link org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource}는
* {@link org.springframework.beans.factory.InitializingBean}을 구현하므로,
* 명시적으로 afterPropertiesSet()메소드를 호출하거나
* 별도 @Bean으로 만들어 Spring Life Cycle을 타도록 해야 한다.
*/
@Bean
public DataSource routingDataSource(@Qualifier("writeDataSource") DataSource writeDataSource, @Qualifier("readDataSource") DataSource readDataSource) {
ReplicationRoutingDataSource routingDataSource = new ReplicationRoutingDataSource();
Map<Object, Object> dataSourceMap = new HashMap<Object, Object>();
dataSourceMap.put("write", writeDataSource);
dataSourceMap.put("read", readDataSource);
routingDataSource.setTargetDataSources(dataSourceMap);
routingDataSource.setDefaultTargetDataSource(writeDataSource);
return routingDataSource;
}
/**
* {@link org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy}로 감싸서
* 트랜잭션 동기화가 이루어진 뒤에 실제 커넥션을 확보하도록 해준다.
*
* @param routingDataSource
* @return
*/
@Bean
public DataSource dataSource(@Qualifier("routingDataSource") DataSource routingDataSource) {
return new LazyConnectionDataSourceProxy(routingDataSource);
}
}