갓생사는 김초원의 개발 블로그
chocho_log
갓생사는 김초원의 개발 블로그
전체 방문자
오늘
어제
  • 분류 전체보기 (77)
    • 개발 (22)
      • Spring (4)
      • Java (3)
      • Database (2)
      • Elasticsearch (3)
      • ETC (3)
      • JPA (3)
      • 이슈 (1)
    • 코딩 테스트 (43)
      • 프로그래머스 (23)
      • 백준 (12)
      • TIP (8)
    • 자료구조 (2)
    • 알고리즘 (4)
    • 잡생각 (0)
    • 경험 (5)
      • AWS re:Invent 2024 (5)

블로그 메뉴

    공지사항

    인기 글

    태그

    • jar
    • Spring Boot Embedded Tomcat
    • war
    • querydsl
    • Lazy Loading
    • 지연로딩
    • jpa
    • 디자인패턴 #SOLID 원칙

    최근 댓글

    최근 글

    갓생사는 김초원의 개발 블로그

    chocho_log

    개발/Spring

    QueryDSL + multi data source 연동하기

    2021. 9. 13. 22:15

    1.QueryDSL + single data source 인 경우

    DataSourceConfiguration

    - entityManagerFactory 생성 메서드

    - 데이터소스 클래스를 생성하는 것이 주 내용이 아니기 때문에 entityManagerFactory 생성 메소드만 올린다. 

        @Bean
        public LocalContainerEntityManagerFactoryBean entityManagerFactory(
                @Qualifier("dataSource") DataSource dataSource) {
            LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
            entityManagerFactoryBean.setDataSource(dataSource);
            entityManagerFactoryBean.setPackagesToScan("com.example.rds.jpa.entity"); // entity 클래스가 있는 패키지 경로
            JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
            entityManagerFactoryBean.setJpaVendorAdapter(vendorAdapter);
            entityManagerFactoryBean.setJpaPropertyMap(hibernateProperties());
            return entityManagerFactoryBean;
        }

     

    QueryDslConfiguration

    - @PersistenceContext로 DataSourceConfiguration에서 생성한 EntityManager를 주입.

    - JPAQueryFactory 빈 등록 

    import com.querydsl.jpa.impl.JPAQueryFactory;
    import javax.persistence.EntityManager;
    import javax.persistence.PersistenceContext;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    /**
     * The type Query dsl configuration.
     */
    @Configuration
    public class QueryDslConfiguration {
    
        @PersistenceContext
        private EntityManager entityManager;
    
        @Bean
        public JPAQueryFactory jpaQueryFactory() {
            return new JPAQueryFactory(entityManager);
        }
    }

     

    JPAQueryFactory 사용

    import com.querydsl.jpa.impl.JPAQueryFactory;
    import org.springframework.data.jpa.repository.support.QuerydslRepositorySupport;
    import org.springframework.stereotype.Repository;
    import org.springframework.util.StringUtils;
    
    import java.util.List;
    
    import static com.example.db.jpa.entity.QTestInfo.testInfo;
    
    /**
     * The type Example Test info repository support.
     */
    @Repository
    public class ExampleTestRepositorySupport extends QuerydslRepositorySupport {
    
        private final JPAQueryFactory queryFactory; // jPAQueryFactory 주입 받아 사용 
    
        /**
         * Instantiates a new Example test repository support.
         *
         * @param queryFactory the query factory
         */
        public ExampleTestRepositorySupport(JPAQueryFactory queryFactory) {
            super(TestInfo.class);
            this.queryFactory = queryFactory;
        }
    
        public List<TestInfo> findTestInfoListBySearch(long test_id) {
            return queryFactory
                    .selectFrom(testInfo)
                    .where(testInfo.testId.eq(test_id))
                    .fetch();
        }
    }

    2.QueryDSL + multi data source 인 경우

    datasource가 2개이고 각각 entityManagerFactory 생성 메소드가 있는 경우에 위와 같이 그대로 구현하면 아래와 같은 오류가 발생한다. 

    Parameter 0 of method setEntityManager in org.springframework.data.jpa.repository.support.QuerydslRepositorySupport required a single bean, but 2 were found:
    	- org.springframework.orm.jpa.SharedEntityManagerCreator#0: defined by method 'createSharedEntityManager' in null
    	- org.springframework.orm.jpa.SharedEntityManagerCreator#1: defined by method 'createSharedEntityManager' in null

     

    QueryDslConfiguration에서 entityManager에 객체 주입을 하는 과정에서  2개의 entityManager 팩토링 생성 메서드 중 어느 것으로 주입을 할지 몰라 생기는 오류다. 

     

    아래와 같이 수정한다. 

    DataSource1Configuration

        /**
         * Entity manager factory local container entity manager factory bean.
         *
         * @param dataSource the data source
         * @return the local container entity manager factory bean
         */
        @Bean
        public LocalContainerEntityManagerFactoryBean entityManagerFactory(
                @Qualifier("dataSource") DataSource dataSource) {
            LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
            entityManagerFactoryBean.setDataSource(dataSource);
            entityManagerFactoryBean.setPackagesToScan("com.example.rds.jpa.entity1");
            entityManagerFactoryBean.setPersistenceUnitName("firstEntityManager"); // 영속성 객체 이름을 지정
            JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
            entityManagerFactoryBean.setJpaVendorAdapter(vendorAdapter);
            entityManagerFactoryBean.setJpaPropertyMap(hibernateProperties());
            return entityManagerFactoryBean;
        }

    DataSource2Configuration

        /**
         * Entity manager factory local container entity manager factory bean.
         *
         * @param dataSource the data source
         * @return the local container entity manager factory bean
         */
        @Bean
        public LocalContainerEntityManagerFactoryBean entityManagerFactory(
                @Qualifier("dataSource") DataSource dataSource) {
            LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
            entityManagerFactoryBean.setDataSource(dataSource);
            entityManagerFactoryBean.setPackagesToScan("com.example.rds.jpa.entity2");
            entityManagerFactoryBean.setPersistenceUnitName("secondEntityManager"); // 영속성 객체 이름을 지정
            JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
            entityManagerFactoryBean.setJpaVendorAdapter(vendorAdapter);
            entityManagerFactoryBean.setJpaPropertyMap(hibernateProperties());
            return entityManagerFactoryBean;
        }

     

    QueryDslConfiguration

    import com.querydsl.jpa.impl.JPAQueryFactory;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    import javax.persistence.EntityManager;
    import javax.persistence.PersistenceContext;
    
    @Configuration
    public class QueryDslConfig {
    
        @PersistenceContext(unitName = "firstEntityManager")
        private EntityManager firstEntityManager;
    
        @PersistenceContext(unitName = "secondEntityManager")
        private EntityManager secondEntityManager;
    
        @Bean
        public JPAQueryFactory firstJpaQueryFactory() {
            return new JPAQueryFactory(firstEntityManager);
        }
    
        @Bean
        public JPAQueryFactory secondJpaQueryFactory() {
            return new JPAQueryFactory(secondEntityManager);
        }
    }

     

    커스텀  QuerydslRepositorySupprt 클래스 구현 (상속으로)

    - setter로 EntityManager를 지정 

    - SecondQuerydslRepositorySupprt 클래스도 마찬가지로 setter에 @PersistenceContext(unitName = "secondEntityManager") 라고 지정하여 구현하면 된다. 

    import org.springframework.data.jpa.repository.support.QuerydslRepositorySupport;
    import org.springframework.stereotype.Repository;
    
    import javax.persistence.EntityManager;
    import javax.persistence.PersistenceContext;
    
    @Repository
    public abstract class FirstQuerydslRepositorySupport extends QuerydslRepositorySupport {
    
        /**
         * Creates a new {@link QuerydslRepositorySupport} instance for the given domain type.
         *
         * @param domainClass must not be {@literal null}.
         */
        public FirstQuerydslRepositorySupport(Class<?> domainClass) {
            super(domainClass);
        }
    
        @Override
        @PersistenceContext(unitName = "firstEntityManager")
        public void setEntityManager(EntityManager entityManager) {
            super.setEntityManager(entityManager);
        }
    }

     

    실제 사용

    - 위에서 구현한 커스텀 QuerydslRepositorySupprt을 상속받아 실세 QuertDSL을 사용하는 클래스를 구현한다. 

    - JPAQueryFactory 객체 주입할 때 @Qualifier 어노테이션으로 특정 빈을 지정

    import com.querydsl.jpa.impl.JPAQueryFactory;
    import org.springframework.data.jpa.repository.support.QuerydslRepositorySupport;
    import org.springframework.stereotype.Repository;
    import org.springframework.util.StringUtils;
    import org.springframework.beans.factory.annotation.Qualifier;
    
    import java.util.List;
    
    import static com.example.db.jpa.entity.QTestInfo.testInfo;
    
    /**
     * The type Example Test info repository support.
     */
    @Repository
    public class ExampleTestRepositorySupport extends QuerydslRepositorySupport {
    
        private final JPAQueryFactory queryFactory; // jPAQueryFactory 주입 받아 사용 
    
        /**
         * Instantiates a new Example test repository support.
         *
         * @param queryFactory the query factory
         */
        public ExampleTestRepositorySupport(@Qualifier("firstJpaQueryFactory")JPAQueryFactory queryFactory) {
            super(TestInfo.class);
            this.queryFactory = queryFactory;
        }
    
        public List<TestInfo> findTestInfoListBySearch(long test_id) {
            return queryFactory
                    .selectFrom(testInfo)
                    .where(testInfo.testId.eq(test_id))
                    .fetch();
        }
    }

    '개발 > Spring' 카테고리의 다른 글

    Spring Boot 배포 WAR 에서 JAR 로 변경하기 (Spring Boot Embedded Tomcat 사용하기)  (2) 2022.04.13
    webflux + reactive redis cache 적용하기  (2) 2021.08.23
    Spring-Cloud-Data-Flow(SCDF)구축해보기  (4) 2020.11.10
      '개발/Spring' 카테고리의 다른 글
      • Spring Boot 배포 WAR 에서 JAR 로 변경하기 (Spring Boot Embedded Tomcat 사용하기)
      • webflux + reactive redis cache 적용하기
      • Spring-Cloud-Data-Flow(SCDF)구축해보기
      갓생사는 김초원의 개발 블로그
      갓생사는 김초원의 개발 블로그
      갓생사는 김초원의 개발 블로그 github: https://github.com/kimchowon

      티스토리툴바