Spring Data JPA 같은 이름, 다른 type인 2개의 @Entity인 경우 주의 사항
가정
- 하나의 project에 의미가 다른 2개의
Event
라는@Entity
가 필요하다. - 당연히 package 경로는 다르다.
- 하나는
net.woniper.data.jpa.event1.Event
(이하 event1) - 하나는
net.woniper.data.jpa.event2.Event
(이하 event2) - package만 다르며, 클래스 명은 같다.
- 하나는
- 각각의 Event는 Repository가 존재한다.
net.woniper.data.jpa.event1.EventRepository
(이하 eventRepository1)net.woniper.data.jpa.event2.EventRepository
(이하 eventRepository2)
예제 코드
net.woniper.data.jpa.event1.Event
package net.woniper.data.jpa.event1;
@Entity
@Table(name = "event1")
@NoArgsConstructor
@ToString
public class Event {
@Id
@GeneratedValue
private Long id;
private String name;
public Event(String name) {
this.name = name;
}
}
net.woniper.data.jpa.event1.EventRepository
package net.woniper.data.jpa.event1;
public interface EventRepository extends CrudRepository<Event, Long> {
List<Event> findByOrderByNameDesc();
}
net.woniper.data.jpa.event2.Event
package net.woniper.data.jpa.event2;
@Entity
@Table(name = "event2")
@NoArgsConstructor
@ToString
public class Event {
@Id
@GeneratedValue
private Long id;
private String name;
public Event(String name) {
this.name = name;
}
}
net.woniper.data.jpa.event2.EventRepository
package net.woniper.data.jpa.event2;
public interface EventRepository extends CrudRepository<Event, Long> {}
위 예제는 package 경로만 다를 뿐 eventRepository1에 findByOrderByNameDesc
메소드를 제외하고 클래스명, 코드 모두 같다.
문제1
예제를 작성한 후 먼저 application을 실행하면 처음 맞이하는 문제가 있다.
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'net.woniper.data.jpa.event1.EventRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
EventRepository
는 Bean
으로 등록되는 시점에 bean name을 EventRepository의 camel case인 eventRepository
로 bean name이 등록된다. 그런데 EventRepository 라는 이름의 Bean 대상이 2개이기 때문에 충돌이 난다.
해결 방법
package net.woniper.data.jpa.event2;
@Repository("event2Repository")
public interface EventRepository extends CrudRepository<Event, Long> {
List<Event> findByOrderByNameDesc();
}
eventRepository2에 bean name을 event2Repository
로 설정했다. 문제 해결!
문제2
net.woniper.data.jpa.event1.EventRepository.findByOrderByNameDesc
메소드 호출 후 실행되는 쿼리를 보자.
select event0_.id as id1_1_, event0_.name as name2_1_ from event2 event0_ order by event0_.name desc
JPA에 의해 생성/실행된 쿼리기 때문에 alias가 조금 보기 힘들지만, 잘 보면 조회한 테이블은 event1
인데, 실행된 쿼리의 테이블이 event2
테이블이다. 어떻게 된걸까?
해결 방법
@Entity(name = "event1")
@Table(name = "event1")
public class Event {}
@Entity(name = "event2")
@Table(name = "event2")
public class Event {}
@Entity의 name 속성을 정의하자. @Entity#name 속성은 default로 클래스 명으로 설정된다. 패키지 명까지 포함되는 게 아니라 클래스 명으로만 name 속성이 기본 정의되기 때문에 문제가 된다. 왜 문제가 되는걸까?
JPA의 쿼리 생성/조회
JPA는 자동으로 쿼리를 만들어준다. 심지어 Spring Data JPA는 QueryMethod라는 기능을 사용해 메소드만으로 쿼리를 만들 수 있는데, 자동으로 쿼리를 생성할때 테이블명을 @Entity#name 속성으로 생성한다. 아래와 같이 말이다.
SELECT * FROM {#entityName} x;
이 내용에 대해서는 Spring Data JPA 문서를 참고하자.
출처 : https://blog.woniper.net/359?category=699184
'Spring Framework > Spring boot' 카테고리의 다른 글
Spring-MVC 읽기 #2. 빌드 (0) | 2020.09.04 |
---|---|
Spring-MVC 읽기 #1. 나는 왜 오픈소스를 읽을까? (0) | 2020.09.04 |
실행 중인 Spring Boot pid 파일 생성 (0) | 2020.09.04 |
CompletableFuture 비동기 처리로 성능 개선하기 (0) | 2020.09.04 |
Spring Batch의 동작 코드 #Step 생성과 실행 (0) | 2020.09.04 |
Spring Batch의 동작 코드 #Job 생성과 실행1 (0) | 2020.09.04 |
누구나 아는 Spring Batch 기본 개념 (0) | 2020.09.04 |
Spring Data REST #3 내부 동작 (0) | 2020.09.04 |