|
|
|
|
@ -37,12 +37,13 @@ import java.util.List;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* DataSource Proxy 설정 클래스
|
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
* datasource-proxy 라이브러리를 사용하여 파라미터 바인딩이 된 실제 SQL 쿼리를 로그로 출력하도록 설정
|
|
|
|
|
* MyBatis의 include, foreach 등 복잡한 쿼리에도 적용됨
|
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
* Environment를 사용하여 수동으로 DataSource를 구성하고 프록시 적용
|
|
|
|
|
*
|
|
|
|
|
* Multi DB 환경 지원
|
|
|
|
|
*
|
|
|
|
|
* @author XIT Framework
|
|
|
|
|
*/
|
|
|
|
|
@Configuration
|
|
|
|
|
@ -52,61 +53,104 @@ public class DataSourceProxyConfig {
|
|
|
|
|
private Environment environment;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 실제 데이터소스 빈 생성
|
|
|
|
|
* Primary 데이터소스 빈 생성
|
|
|
|
|
* Environment에서 설정값을 읽어서 HikariDataSource를 수동으로 구성
|
|
|
|
|
*/
|
|
|
|
|
@Bean
|
|
|
|
|
public DataSource actualDataSource() {
|
|
|
|
|
return createHikariDataSource("spring.datasource");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Secondary 데이터소스 빈 생성 (필요한 경우)
|
|
|
|
|
* Multi DB 환경에서 두 번째 DB를 사용할 경우 활성화
|
|
|
|
|
*
|
|
|
|
|
* 예시:
|
|
|
|
|
* @Bean
|
|
|
|
|
* public DataSource actualSecondaryDataSource() {
|
|
|
|
|
* return createHikariDataSource("spring.datasource.secondary");
|
|
|
|
|
* }
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* HikariDataSource 생성 헬퍼 메서드
|
|
|
|
|
*
|
|
|
|
|
* @param prefix application.yml의 설정 prefix
|
|
|
|
|
* @return HikariDataSource
|
|
|
|
|
*/
|
|
|
|
|
private HikariDataSource createHikariDataSource(String prefix) {
|
|
|
|
|
HikariDataSource dataSource = new HikariDataSource();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// application.yml에서 설정값 읽기
|
|
|
|
|
dataSource.setJdbcUrl(environment.getProperty("spring.datasource.url"));
|
|
|
|
|
dataSource.setUsername(environment.getProperty("spring.datasource.username"));
|
|
|
|
|
dataSource.setPassword(environment.getProperty("spring.datasource.password"));
|
|
|
|
|
dataSource.setDriverClassName(environment.getProperty("spring.datasource.driver-class-name"));
|
|
|
|
|
|
|
|
|
|
dataSource.setJdbcUrl(environment.getProperty(prefix + ".url"));
|
|
|
|
|
dataSource.setUsername(environment.getProperty(prefix + ".username"));
|
|
|
|
|
dataSource.setPassword(environment.getProperty(prefix + ".password"));
|
|
|
|
|
dataSource.setDriverClassName(environment.getProperty(prefix + ".driver-class-name"));
|
|
|
|
|
|
|
|
|
|
// HikariCP 설정
|
|
|
|
|
dataSource.setMaximumPoolSize(environment.getProperty("spring.datasource.hikari.maximum-pool-size", Integer.class, 10));
|
|
|
|
|
dataSource.setMinimumIdle(environment.getProperty("spring.datasource.hikari.minimum-idle", Integer.class, 5));
|
|
|
|
|
dataSource.setConnectionTimeout(environment.getProperty("spring.datasource.hikari.connection-timeout", Long.class, 30000L));
|
|
|
|
|
dataSource.setIdleTimeout(environment.getProperty("spring.datasource.hikari.idle-timeout", Long.class, 600000L));
|
|
|
|
|
dataSource.setMaxLifetime(environment.getProperty("spring.datasource.hikari.max-lifetime", Long.class, 1800000L));
|
|
|
|
|
dataSource.setValidationTimeout(environment.getProperty("spring.datasource.hikari.validation-timeout", Long.class, 60000L));
|
|
|
|
|
|
|
|
|
|
dataSource.setMaximumPoolSize(environment.getProperty(prefix + ".hikari.maximum-pool-size", Integer.class, 10));
|
|
|
|
|
dataSource.setMinimumIdle(environment.getProperty(prefix + ".hikari.minimum-idle", Integer.class, 5));
|
|
|
|
|
dataSource.setConnectionTimeout(environment.getProperty(prefix + ".hikari.connection-timeout", Long.class, 30000L));
|
|
|
|
|
dataSource.setIdleTimeout(environment.getProperty(prefix + ".hikari.idle-timeout", Long.class, 600000L));
|
|
|
|
|
dataSource.setMaxLifetime(environment.getProperty(prefix + ".hikari.max-lifetime", Long.class, 1800000L));
|
|
|
|
|
dataSource.setValidationTimeout(environment.getProperty(prefix + ".hikari.validation-timeout", Long.class, 60000L));
|
|
|
|
|
|
|
|
|
|
return dataSource;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 프록시 데이터소스 빈 생성 (Primary)
|
|
|
|
|
* Primary 프록시 데이터소스 빈 생성
|
|
|
|
|
* actualDataSource를 래핑하여 SQL 쿼리 로깅 기능을 추가
|
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
* @param actualDataSource 실제 데이터소스
|
|
|
|
|
* @return 프록시가 적용된 데이터소스
|
|
|
|
|
*/
|
|
|
|
|
@Bean
|
|
|
|
|
@Primary
|
|
|
|
|
public DataSource dataSource(@Qualifier("actualDataSource") DataSource actualDataSource) {
|
|
|
|
|
return createProxyDataSource(actualDataSource, "PRIMARY-DB");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Secondary 프록시 데이터소스 빈 생성 (필요한 경우)
|
|
|
|
|
* Multi DB 환경에서 두 번째 DB를 사용할 경우 활성화
|
|
|
|
|
*
|
|
|
|
|
* 예시:
|
|
|
|
|
* @Bean
|
|
|
|
|
* public DataSource secondaryDataSource(@Qualifier("actualSecondaryDataSource") DataSource actualSecondaryDataSource) {
|
|
|
|
|
* return createProxyDataSource(actualSecondaryDataSource, "SECONDARY-DB");
|
|
|
|
|
* }
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 프록시 데이터소스 생성 헬퍼 메서드
|
|
|
|
|
*
|
|
|
|
|
* @param actualDataSource 실제 데이터소스
|
|
|
|
|
* @param dataSourceName 데이터소스 이름 (로그 식별용)
|
|
|
|
|
* @return 프록시가 적용된 데이터소스
|
|
|
|
|
*/
|
|
|
|
|
private DataSource createProxyDataSource(DataSource actualDataSource, String dataSourceName) {
|
|
|
|
|
// SLF4J 쿼리 로깅 리스너 생성
|
|
|
|
|
SLF4JQueryLoggingListener loggingListener = new SLF4JQueryLoggingListener();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 로그 레벨 설정 (DEBUG 레벨로 출력)
|
|
|
|
|
loggingListener.setLogLevel(SLF4JLogLevel.DEBUG);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 로거 이름 설정 (쿼리 로그 식별을 위함)
|
|
|
|
|
loggingListener.setLogger("go.kr.project.sql");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 쿼리 로그 엔트리 생성자 설정
|
|
|
|
|
DefaultQueryLogEntryCreator logEntryCreator = new DefaultQueryLogEntryCreator();
|
|
|
|
|
logEntryCreator.setMultiline(true); // 멀티라인으로 보기 좋게 출력
|
|
|
|
|
loggingListener.setQueryLogEntryCreator(logEntryCreator);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 커스텀 파라미터 바인딩 리스너 생성
|
|
|
|
|
CustomParameterBindingListener customListener = new CustomParameterBindingListener();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 프록시 데이터소스 빌더를 사용하여 프록시 데이터소스 생성
|
|
|
|
|
return ProxyDataSourceBuilder
|
|
|
|
|
.create(actualDataSource)
|
|
|
|
|
.name("IBMS-NEW-DB") // 데이터소스 이름 설정
|
|
|
|
|
.name(dataSourceName) // 데이터소스 이름 설정
|
|
|
|
|
.listener(loggingListener) // 기본 로깅 리스너 추가
|
|
|
|
|
.listener(customListener) // 커스텀 파라미터 바인딩 리스너 추가
|
|
|
|
|
.asJson() // JSON 형태로 파라미터 바인딩된 쿼리 출력
|
|
|
|
|
|