사이드 프로젝트에서는 당연하지만
이전 회사에서도 한 프로그램에 데이터베이스를 여러개 쓰는 일은 없었다.
찾아보니 그런 일이 아예 없는 건 아니고 규모가 크면 클수록 여러개를 쓰는 일이 있기는 하다고 하더라.
혹은 Mybatis -> JPA로 전환하는 과정이나 기타 마이그레이션 작업에도 쓸 수 있겠다.
다른 프로젝트 일 좀 도와주다가 데이터베이스를 두개 설정해놓은 경우를 봤다.
DatabaseConfig 라는 파일을 하나 생성해주고 시작하자.
참고로 내가 사용하는 방식은 JPA + 기타 데이터베이스 형태라고 보면 되겠다.
목차
JPA를 적용한 DatabaseConfig 설정
@Configuration
@EnableTransactionManagement(proxyTargetClass = true)
@EnableJpaRepositories(
entityManagerFactoryRef = "${entitymanager_별칭}",
transactionManagerRef = "${transaction_별칭}",
basePackages = {"${레포지토리_패키지_경로}"}
)
@RequiredArgsConstructor
public class DatabaseConfig {
private final Environment env;
@Bean
@Primary
@ConfigurationProperties(prefix = "spring.datasource.first")
public DataSource firstDataSource() {
return DataSourceBuilder.create().type(HikariDataSource.class).build();
}
@Bean
@Primary
public SqlSessionTemplate firstSqlSessionTemplate(SqlSessionFactory sqlSessionFactory) throws Exception{
return new SqlSessionTemplate(sqlSessionFactory);
}
@Bean(name = "${entitymanager_별칭}")
public LocalContainerEntityManagerFactoryBean contentsEntityManagerFactory(
EntityManagerFactoryBuilder builder
, @Qualifier("firstDataSource") DataSource dataSource
) {
Map<String, String> propertiesHashMap = new HashMap<>();
propertiesHashMap.put("hibernate.dialect", env.getProperty("spring.jpa.hibernate.dialect"));
propertiesHashMap.put("hibernate.hbm2ddl.auto", env.getProperty("spring.jpa.hibernate.ddl-auto"));
propertiesHashMap.put("hibernate.show_sql", env.getProperty("spring.jpa.show-sql"));
propertiesHashMap.put("hibernate.format_sql", env.getProperty("spring.jpa.properties.hibernate.form_sql"));
return builder.dataSource(dataSource).packages("${entity 패키지 경로}")
.properties(propertiesHashMap).build();
}
@Bean(name = "${transaction_별칭}")
public JpaTransactionManager transactionManager(
@Qualifier("${entitymanager_별칭}") LocalContainerEntityManagerFactoryBean mfBean
) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(mfBean.getObject());
return transactionManager;
}
우선 JPA만 사용한다고 가정하고 DatabaseConfig 클래스에 선언하는 어노테이션들이다. 그에 대한 별칭을 선언하고 시작하자.
//트랜잭션 처리를 허용하는 어노테이션
@EnableTransactionManagement(proxyTargetClass = true)
//JPARepository들을 사용하기 위한 어노테이션으로 선언 내용은 본인이 설정하는 별칭으로 작성하면 된다.
@EnableJpaRepositories(
entityManagerFactoryRef = "firstJpaEntityManagerFactory",
transactionManagerRef = "firstTransactionManager",
basePackages = {"com.xxx.xxx.repository"}
)
1. DataSource
@Bean
//기본으로 사용하겠다.
@Primary
//properties에서 사용하는 config이름으로 설정하겠다.
@ConfigurationProperties(prefix = "spring.datasource.first")
//함수명은 편한대로 지으면 된다. 여러개니까 구분이 갈 수 있도록만 지으면 된다.
public DataSource firstDataSource() {
return DataSourceBuilder.create().type(HikariDataSource.class).build();
}
위처럼 ConfigurationProperties를 설정하고 나면 properties에서 아래처럼 설정을 선언할 수 있다.
spring.datasource.first.driverClassName=org.postgresql.Driver
spring.datasource.first.jdbc-url=jdbc:postgresql://localhost:5432/xxx
spring.datasource.first.username=xxxxx
spring.datasource.first.password=xxxxx
2. LocalContainerEntityManagerFactoryBean
우리가 앞서 properties를 설정하기 위해 DataSource 이름을 설정했고 properties에 설정을 끝마쳤다고 가정해보자. 그리고 그 설정들을 EntityManagerFactory에 설정해 줄 필요가 있겠다.
@Bean(name = "firstJpaEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean contentsEntityManagerFactory(
EntityManagerFactoryBuilder builder
, @Qualifier("firstDataSource") DataSource dataSource
) {
Map<String, String> propertiesHashMap = new HashMap<>();
propertiesHashMap.put("hibernate.dialect", env.getProperty("spring.jpa.hibernate.dialect"));
propertiesHashMap.put("hibernate.hbm2ddl.auto", env.getProperty("spring.jpa.hibernate.ddl-auto"));
propertiesHashMap.put("hibernate.show_sql", env.getProperty("spring.jpa.show-sql"));
propertiesHashMap.put("hibernate.format_sql", env.getProperty("spring.jpa.properties.hibernate.form_sql"));
return builder.dataSource(dataSource).packages("com.xxx..entity")
.properties(propertiesHashMap).build();
}
3. TransactionManager
//DatabaseConfig 클래스에서 선언했던 transactionManagerRef이름을 선언해주면 된다.
//서비스계층에서 이 빈을 사용하게 된다. 여러 데이터베이스를 사용하다 보니 어떤 transactionManager를 사용할 지 결정한다고 보면 되겠다.
@Bean(name = "firstTransactionManager")
public JpaTransactionManager firstTransactionManager(
@Qualifier("firstJpaEntityManagerFactory") LocalContainerEntityManagerFactoryBean mfBean
) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(mfBean.getObject());
return transactionManager;
}
서비스계층에서 사용하는 방법이다.
@Service
@Transactional(value ="firstTransactionManager")
@RequiredArgsConstructor
public class UserService {
SQLMapper를 이용한 DatabaseConfig 두번째 설정
@Configuration
@MapperScan(basePackages = "${패키지경로}")
@RequiredArgsConstructor
public class DatabaseConfig {
private final Environment env;
@Bean
@ConfigurationProperties(prefix = "spring.datasource.second")
public DataSource secondDataSource() {
return DataSourceBuilder.create().type(HikariDataSource.class).build();
}
@Bean
public SqlSessionFactory secondSqlSessionFactory(@Qualifier("${DataSource별칭}") DataSource dataSource, ApplicationContext applicationContext) throws Exception{
SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
sessionFactory.setDataSource(dataSource);
Resource[] res = new PathMatchingResourcePatternResolver().getResources("classpath:${mapper경로}");
sessionFactory.setMapperLocations(res);
return sessionFactory.getObject();
}
@Bean
public SqlSessionTemplate secondSqlSessionTemplate(SqlSessionFactory sqlSessionFactory) throws Exception{
return new SqlSessionTemplate(sqlSessionFactory);
}
@Bean
public PlatformTransactionManager secondTransactionManager(@Qualifier("${DataSource별칭}") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
1. DataSource
@Bean
@ConfigurationProperties(prefix = "spring.datasource.second")
public DataSource secondDataSource() {
return DataSourceBuilder.create().type(HikariDataSource.class).build();
}
두번째 데이터베이스에 대한 설정도 properties에 해주면 된다.
spring.datasource.second.driver-class-name=net.sf.log4jdbc.sql.jdbcapi.DriverSpy
spring.datasource.second.jdbc-url=jdbc:log4jdbc:mariadb://xxxxxx/xxx
spring.datasource.second.username=xxx
spring.datasource.second.password=xxx
2. SqlSessionFactory
@Bean
public SqlSessionFactory secondSqlSessionFactory(@Qualifier("secondDataSource") DataSource dataSource, ApplicationContext applicationContext) throws Exception{
SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
sessionFactory.setDataSource(dataSource);
Resource[] res = new PathMatchingResourcePatternResolver().getResources("classpath:static/mapper/second/**.xml");
sessionFactory.setMapperLocations(res);
return sessionFactory.getObject();
}
어느 경로에 있는 mapper와 매칭을 시켜서 로드 및 설정할 것인가. 정도로 보면 되겠다.
3. SqlSessionTemplate
@Bean
public SqlSessionTemplate secondSqlSessionTemplate(SqlSessionFactory sqlSessionFactory) throws Exception{
return new SqlSessionTemplate(sqlSessionFactory);
}
4. TransactionManager
@Bean
public PlatformTransactionManager secondTransactionManager(@Qualifier("secondDataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
'IT이야기 > LANGUAGE' 카테고리의 다른 글
[SpringBoot] SpringBoot 3.0 이상의 SecurityConfig 설정 - 람다식으로 변경 (0) | 2024.03.21 |
---|---|
[Java/Spring] 개선된 아키텍쳐로 리팩토링 & 자바 테스트 (1) | 2024.01.21 |
[JAVA / SpringBoot] Controller와 POSTMAN 테스트 예시(DTO, LIST, RequestPart, Multipart) (1) | 2024.01.19 |