JPA Multiple DataSource 설정 방법

드라카·2022년 12월 20일
0

기본적인 멀티 데이터 베이스 설정 부터 간단한 접속 테스트까지의 과정을 정리해 봅니다.

필자는 Oracle+Mysql 환경으로 진행하였으며, 다른 DB 를 사용하시는 분들은 그에 맞게 datasource 를 변경해 주면 되겠습니다.

1. 개발환경

SpringBoot 2.7.6
JDK 1.8
Oracle+Mysql
Log4Jdbc
junit4

2. build.gradle

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation group: 'mysql', name: 'mysql-connector-java', version: '8.0.29'
    compileOnly 'org.projectlombok:lombok'
    runtimeOnly 'com.microsoft.sqlserver:mssql-jdbc'
    runtimeOnly 'com.oracle.database.jdbc:ojdbc8'
    annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
    annotationProcessor 'org.projectlombok:lombok'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    testImplementation group: 'junit', name: 'junit', version: '4.13.2'
    implementation group: 'com.oracle.ojdbc', name: 'orai18n', version: '19.3.0.0'

    implementation 'org.bgee.log4jdbc-log4j2:log4jdbc-log4j2-jdbc4.1:1.16'
}

3. application.yml

server:
  port: 8080

spring:
  profiles:
    active: live
    
---    
spring:
  config:
    activate:
      on-profile: live
  jpa:
    open-in-view: true
    hibernate:
      ddl-auto: none
      naming:
        physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
      use-new-id-generator-mappings: false
    show-sql: true
    properties:
      hibernate.format_sql: true
  jackson:
    serialization:
      fail-on-empty-beans: false
  oracle-datasource:
    driverClassName: net.sf.log4jdbc.sql.jdbcapi.DriverSpy
    jdbcUrl: jdbc:log4jdbc:oracle:thin:@localhost:1521:TEST
    username: ****
    password: ****
  mysql-datasource:
    driverClassName: net.sf.log4jdbc.sql.jdbcapi.DriverSpy
    jdbcUrl: jdbc:log4jdbc:mysql://localhost:3306/TEST
    username: ****
    password: ****

jpa 설정은 다양한 케이스가 존재하므로 각자에 맞는 설정값을 찾아보도록 하자.

datasource 명으로 각각의 db를 구분하도록 한다.

4. Entity

Datasource 별로 별도의 패키지를 생성하도록 하자

mysql-datasource User.java

package com.draka.entity.mysql;

@Data
@Entity
public class User {
	@Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;
    
    @Column(nullable = false, length = 30, unique = true)
    private String username;
}

oracle-datasource Company.java

package com.draka.entity.oracle;

@Data
@Entity
public class Company {
	@Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;
    
    @Column(nullable = false, length = 30, unique = true)
    private String companyname;
}

5. Repository

mysql-datasource UserRepository.java

package com.draka.repository.mysql;

@Repository
public interface UserRepository extends JpaRepository<User, Long> {
}

oracle-datasource CompanyRepository.java

package com.draka.repository.oracle;

@Repository
public interface CompanyRepository extends JpaRepository<Company, Long> {
}

6. Configuration 설정작업

Mysql Database 를 Primary Database 로 설정하였다.

MysqlDataSourceCofig.java

package com.draka.config;

@Configuration
@EnableJpaRepositories(
        basePackages = "com.draka.repository.mysql",
        entityManagerFactoryRef = "mysqlEntityManager",
        transactionManagerRef = "mysqlTransactionManager"
)
public class MysqlDataSourceConfig {
    @Bean
    @Primary
    public LocalContainerEntityManagerFactoryBean mysqlEntityManager() {
        LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();

        em.setDataSource(mysqlDataSource());
        em.setPackagesToScan(new String[]{"com.draka.entity.mysql"});
        em.setJpaVendorAdapter(new HibernateJpaVendorAdapter());

        return em;
    }

    @Bean
    @Primary
    @ConfigurationProperties(prefix = "spring.mysql-datasource")
    public DataSource mysqlDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean
    @Primary
    public PlatformTransactionManager mysqlTransactionManager() {
        JpaTransactionManager transactionManager = new JpaTransactionManager();

        transactionManager.setEntityManagerFactory(mysqlEntityManager().getObject());

        return transactionManager;
    }
}

OracleDataSourceCofig.java

package com.draka.config;

@Configuration
@EnableJpaRepositories(
        basePackages = "com.draka.repository.oracle",
        entityManagerFactoryRef = "oracleEntityManager",
        transactionManagerRef = "oracleTransactionManager"
)
public class OracleDataSourceConfig {
    @Bean
    public LocalContainerEntityManagerFactoryBean oracleEntityManager() {
        LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();

        em.setDataSource(oracleDataSource());
        em.setPackagesToScan(new String[]{"com.draka.entity.oracle"});
        em.setJpaVendorAdapter(new HibernateJpaVendorAdapter());

        return em;
    }

    @Bean
    @ConfigurationProperties(prefix = "spring.oracle-datasource")
    public DataSource oracleDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean
    public PlatformTransactionManager oracleTransactionManager() {
        JpaTransactionManager transactionManager = new JpaTransactionManager();

        transactionManager.setEntityManagerFactory(oracleEntityManager().getObject());

        return transactionManager;
    }
}

7. Test

@RunWith(SpringRunner.class)
@SpringBootTest
@EnableTransactionManagement
public class MultipleJpaTest {
    @Autowired
    UserRepository userRepository;

    @Autowired
    CompanyRepository companyRepository;

    @Test
    @Transactional("mysqlTransactionManager")
    public void Mysql정상접속여부() {
        assertTrue(userRepository.count() > 0, "접속성공");
    }

    @Test
    @Transactional("oracleTransactionManager")
    public void Oracle정상접속여부() {
        assertTrue(companyRepository.count() > 0, "접속성공");
    }
}

profile
삽질의 달인

1개의 댓글

comment-user-thumbnail
2024년 4월 16일

좋은 내용 잘 보고 갑니다.
감사합니다.

답글 달기