일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 |
- tomcat
- spring batch 코드
- Spring Data REST
- docker
- IntelliJ
- spring bean
- 코드 리뷰
- spring-webmvc
- JPA mapping
- batch
- JPA
- spring boot
- Data REST
- Spring Data JPA
- 톰캣
- static inner class
- Spring
- JUnit
- REST API
- spring-webmvc #코드읽기
- spring camp
- ORM
- Spring Batch
- SuperTypeToken
- spring-mvc
- ApplicationPidFileWriter
- 세미나
- spring pid
- spring boot tomcat
- spring jpa
- Today
- 1
- Total
- 916,386
woniper
Spring Data JPA 같은 이름, 다른 type인 2개의 @Entity인 경우 주의 사항 본문
Spring Data JPA 같은 이름, 다른 type인 2개의 @Entity인 경우 주의 사항
woniper1 2018. 5. 24. 12:30가정
- 하나의 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 문서를 참고하자.
'Spring' 카테고리의 다른 글
실행 중인 Spring Boot pid 파일 생성 (0) | 2018.09.22 |
---|---|
CompletableFuture 비동기 처리로 성능 개선하기 (0) | 2018.09.08 |
Spring Batch의 동작 코드 #Step 생성과 실행 (2) | 2018.05.08 |
Spring Batch의 동작 코드 #Job 생성과 실행 (0) | 2018.05.04 |
누구나 아는 Spring Batch 기본 개념 (2) | 2018.04.30 |