Spring/초기 setting

3) JPA 다중 스키마 설정

쿠카이든 2023. 3. 19. 23:06
728x90
JPA 다중 스키마 설정

 

아래 내용은 https://github.com/beaver84/setting-test 에서 실제 소스를 확인할 수 있습니다.

  • JPA 구조
    • Persistence: EntityManagerFactory 인스턴스를 얻기 위한 정적 메서드를 포함하는 클래스이다.
    • EntityManagerFactory: EntityManager의 팩토리 클래스입니다. EntityManager의 여러 인스턴스를 생성하고 관리한다.
    • EntityManager: 개체에 대한 지속성 작업을 제어하는 인터페이스이다. 쿼리 인스턴스에서 작동합니다.
    • Entity 엔터티는 데이터베이스에 레코드로 저장되는 persistence 개체입니다.
    • Persistence Unit: 모든 엔터티 클래스 집합을 정의합니다. 애플리케이션에서는 EntityManager 인스턴스가 이를 관리합니다. 엔티티 클래스 집합은 단일 데이터 저장소에 포함된 데이터를 나타냅니다.
    • EntityTransaction: EntityManager 클래스와 일대일 관계를 가집니다 . 각 EntityManager에 대해 작업은 EntityTransaction 클래스에 의해 유지 관리됩니다.
    • Query: 기준에 맞는 관계 객체를 얻기 위해 각 JPA 벤더에서 구현하는 인터페이스이다.

Architecture of Java Persistence API(참고: https://www.javatpoint.com/spring-boot-jpa)

 

  • 앞선 글에 Mybatis 설정 완료된 프로젝트에 이어서 JPA 설정을 추가한다.
  • 먼저 build.gradle 에 아래 라이브러리를 추가하고 코끼리 모양 버튼을 클릭하여 새로고침을 한다.
dependencies {
    
    ...
    // JPA 라이브러리 추가 (기존에 있으면 추가안해도 무방함)
    implementation 'org.springframework.data:spring-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    ...
}

 

  • 다음에 application.properties 파일을 수정한다.
(기존 내용 아래 추가)
teamflace.jpa.datasource.master.jdbc-url=jdbc:log4jdbc:mysql://localhost:3306/[스키마명]?characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true&autoReconnection=true
teamflace.jpa.datasource.master.username=[아이디]
teamflace.jpa.datasource.master.password=[비밀번호]
teamflace.jpa.database=mysql
teamflace.jpa.hibernate.use-new-id-generator-mappings=false
teamflace.jpa.show-sql=true
#데이터베이스 방언을 프로젝트 main DB인 MySQL로 설정
teamflace.jpa.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
#JPA Lazy 타입 조회 시, N+1(1+N) 현상 발생 방지
teamflace.jpa.properties.hibernate.default_batch_fetch_size=1000

 

  • 이제 application.properties의 내용을 컨테이너에 주입할 config 파일을 만들어야 한다.
  • 그러기 위해 config 패키지 밑에 JpaConfig.java 파일을 만든다.
  • repository 패키지 하위에 jpa 패키지를 미리 만들어야 한다(JPA 설정을 적용할 basePackage 지정) .
  • @EnableJpaRepositories(basePackages = "com.example.settingtest.repository.jpa" 에는 위에 만든 패키지의 풀네임을 입력한다.
  • 마지막으로 em.setPackagesToScan("com.example.settingtest.domain") 에는 실제 entity가 저장되는 패키지 위치를 입력한다.

JpaConfig 파일 위치

(임포트 구문 생략)

@Configuration
@Lazy
@EnableTransactionManagement
@EnableJpaRepositories(basePackages = "com.example.settingtest.repository.jpa", entityManagerFactoryRef = "jpaTestEntityManagerFactory")
@EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class})
public class JpaConfig {

    private Logger log = LogManager.getLogger(this.getClass());

    private Properties properties;

    @Autowired
    public JpaConfig(@Qualifier("jpaTestDatasourceProperties") Properties properties) {
        this.properties = properties;
    }
    
    //application.properties 파일에 jpaTest.jp로 시작하는 접속 정보를 Properties에 가져온다.
    @ConfigurationProperties(prefix = "jpaTest.jpa")
    @Bean(name = "jpaTestDataSourceProperties")
    public Properties jpaTestDataSourceProperties() {
        return new Properties();
    }
    
    //위에서 만들어진 properties 정보를 바탕으로 spring JDBC에 필요한 dataSource를 생성
    @Bean(name = "jpaTestDatasource")
    public DataSource jpaTestDatasource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        log.info("teamflaceJpaDatasource  ===> {}", dataSource);
        dataSource.setDriverClassName(properties.getProperty("driver-class-name"));
        dataSource.setUrl(properties.getProperty("url"));
        dataSource.setUsername(properties.getProperty("username"));
        dataSource.setPassword(properties.getProperty("password"));

        return dataSource;
    }
    
    //위에서 만들어진 datasource를 바탕으로 JPA에 영속성 컨텍스트인 EntityManager를 만든다.
    //또한 이를 생성하는 EntityManagerFactory를 만든다.
    @Bean(name = "jpaTestEntityManagerFactory")
    public LocalContainerEntityManagerFactoryBean jpaTestEntityManagerFactory() throws Exception {
        LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
        em.setDataSource(jpaTestDatasource());
        em.setPackagesToScan("[실제 entity가 저장되는 패키지]");
        HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        em.setJpaVendorAdapter(vendorAdapter);
        em.setJpaProperties(jpaTestDataSourceProperties());
        log.info("jpaTestDataSourceProperties ===> {}", jpaTestDataSourceProperties());

        return em;
    }
    
    //위에서 만든 EntityManager와 EntityManagerFactory 정보를 바탕으로 TransactionManager를 만든다.
    //서비스단에서 @Transactional로 사용할 수 있다.
    //Mybatis와 같이 사용하기 위해 작업을 한 트랜잭션으로 묶기 위한 배경작업
    @Bean(name = "jpaTestTransactionManager")
    public PlatformTransactionManager jpaTestTransactionManager() throws Exception {
        JpaTransactionManager transactionManager = new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(jpaTestEntityManagerFactory().getObject());
        log.info("teamflaceJpaTransactionManager  ===> {}", transactionManager);
        return transactionManager;
    }         
}
  • @EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class}) 는 기본 설정과 겹치는 부분이 있는 경우 무시하는 설정방법이다(어떤 설정을 가져왔는지 몰라서 생기는 오류 발생 방지).
  • @Configuration 안에 @Bean이 4개 있는데 차례대로 간략히 설명하자면 다음과 같다.
    • Properties teamflaceJpaDataSourceProperties() - application.properties 파일에 패키지명의 prefix 로 시작하는 접속 정보를 Properties에 가져옴
    • DataSource teamflaceJpaDatasource() - properties 정보를 바탕으로 spring JDBC에 필요한 dataSource 를 생성
    • LocalContainerEntityManagerFactoryBean teamfleshEntityManagerFactory() - datasource 를 바탕으로 JPA에 Entity를 관리하는 EntityManager, 또한 이를 생성하는 EntityManagerFactory 를 만든다.
    • PlatformTransactionManager teamflaceJpaTransactionManager() - EntityManager와 EntityManagerFactory 정보를 바탕으로 TransactionManager를 만든다. PlatformTransactionManager의 구현체 중에 JpaTransactionManager를 활용하였다.

참고로 기본 구현체는 DataSourceTxManager이고, SpringDataJPA 사용시 JpaTxManager로 설정을 바꾼다.

728x90
  • 이제 Mybatis와 한 트랜잭션으로 묶어서 관리하기 위해 Mybatis 설정에서 만들었던 RdbConnectionConfiguration을 수정한다.
  • Qualifier에 설정된 빈과 같은 이름으로 찾아가 패키지에 따라 Mybatis 혹은 JPA로 DB 연동 작업을 수행하게 된다.
(임포트 구문 생략)
@Configuration
@Lazy
@EnableTransactionManagement
public class RdbConnectionConfiguration {

    @Bean(name = "transactionManager")
    @Primary
    public PlatformTransactionManager transactionManager(
            @Qualifier("mybatisTransactionManager") PlatformTransactionManager mybatisTransactionManager,
            @Qualifier("jpaTestTransactionManager") PlatformTransactionManager jpaTestTransactionManager) {
        return new ChainedTransactionManager(
                mybatisTransactionManager,
                jpaTestTransactionManager);
    }
}

 

  • 이제 JPA 설정이 완료됐으며 테스트 코드를 통해 테스트를 진행한다.
  • 아래 위치에 repository 파일을 추가한다.

@Repository
public interface MemberJpaRepository extends JpaRepository<Member, Long> {
    Member findByEmail(String email);
}

 

  • 기존 엔티티에 @Entity, @Id 속성을 추가한다.

 

  • test 코드를 작성한다.
import static org.assertj.core.api.Assertions.assertThat;

@SpringBootTest
@Transactional
class MemberJpaRepositoryTest {

    @Autowired
    MemberJpaRepository memberJpaRepository;

    @BeforeEach
    public void setUp() {
        //setup before testing
        memberJpaRepository.deleteAll();
    }

    @Test
    @DisplayName("이메일로 멤버 조회 JPA 테스트")
    void findByEmail() {
        //given : 멤버 정보가 주어졌을 때
        Member member = new Member();
        member.setEmail("beaver@timf.co.kr");
        member.setName("배비버");
        member.setAddress("경기도 부천");
        member.setPassword("1123");

        memberJpaRepository.save(member);

        //when : 이메일로 단건조회를 하면
        Member memberResult = memberJpaRepository.findByEmail("eden@timf.co.kr");

        //then : 해당 유저 정보를 조회할 수 있다.
        assertThat(memberResult.getId()).isGreaterThanOrEqualTo(1);
        assertThat(memberResult.getEmail()).isEqualTo("beaver@timf.co.kr");
        assertThat(memberResult.getName()).isEqualTo("배비버");
        assertThat(memberResult.getAddress()).isEqualTo("경기도 부천");
        assertThat(memberResult.getPassword()).isEqualTo("1123");

    }
}

  • 테스트가 정상적으로 수행되었고 JPA 셋팅이 완료되었다.

 

참고: https://www.javatpoint.com/spring-boot-jpa

 

Spring Boot JPA - javatpoint

Spring Boot JPA with features, project, starter project wizard, cli, application, annotations, dm, properties, actuator, thymeleaf view, jpa, jdbc

www.javatpoint.com

 

728x90