JPA 정의
JAVA에서 ORM (Object - Relational Mapping) 기술 표준으로 사용되는 인터페이스의 모음
ORM 정의 객체 ↔ DB 연결한다는 뜻
장점
생산성 증가, 코드 가독성 증가
CREATE(INSERT) | save() |
READ | findBy |
UPDATE | save() |
DELETE | delete() |
단계 | MyBatis | JPA |
SQL 작성 방식 | XML 파일에서 SQL 직접 작성 | 엔티티 클래스를 통해 자동으로 SQL 생성 |
Mapper | Mapper 인터페이스와 XML 매핑 | Repository 인터페이스와 엔티티 클래스 매핑 |
SQL 실행 | SQL 쿼리를 수동으로 작성하고 매퍼에서 실행 | save 메서드 호출로 JPA가 SQL 자동 생성 및 실행 |
데이터 객체 변환 | 수동으로 DTO와 매핑 | 엔티티 클래스와 자동 매핑 |
프로젝트 세팅부터 위 요소들을 합하면 개발 속도나 유지 보수 측면에서 이점이 많다.
하지만 myBatis 가 무작정 나쁜 건 아니다.
sql문만 변경하면 java 소스 코드를 수정하지 않고 손쉽게 원하는 데이터를 얻을 수 있다.
단점
TABLE 간에 연관 관계가 많은 데이터의 경우 JOIN이 불가피한데, 방식이 생각보다 고려할 점이 많다.
첫 번째 방법 : JPA에서 DTO Projection을 자동으로 처리하는 방법 (Query 없이)
게시판과 사용자가 있다고 할 경우 연결하려면 아래와 같다.
tbl_board 테이블의 엔티티 Board의 user_seq_no와 tbl_user 테이블의 seq_no 가
조인되는 컬럼이라는 걸 어노테이션을 통해 명시한다.
@Entity
@Table(name = "tbl_board")
public class Board {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long seqNo;
private String title;
private String content;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_seq_no")
private User user;
연관관계 | JPA Annotation |
1:1 | @OneToOne |
1:N | @OneToMany |
N:1 | @ManyToOne |
N:M | @ManyToMany |
게시판의 글은 한 사용자가 많이 작성할 수 있기 때문에 N : 1 인 ManyToOne 사용
Fetchype.LAZY (지연 로딩)
연관된 엔티티를 실제로
필요한 시점에만 조회
FetchType.EAGER (즉시 로딩)
엔티티가 조회될 때
연관된 모든 엔티티를 한 번에 조회
public class BoardUserDTO {
private Long boardId;
private String title;
private String content;
private String userName;
private String userPhone;
public BoardUserDTO(Long boardId, String title, String content,
String userName, String userPhone) {
this.boardId = boardId;
this.title = title;
this.content = content;
this.userName = userName;
this.userPhone = userPhone;
}
// Getters and setters
}
@Repository
public interface BoardRepository extends JpaRepository<Board, Long> {
List<BoardUserDTO> findByUserSeqNo(Long userSeqNo);
}
그 이후엔 Repository 에서 조건에 맞게 사용하면 끝!
두 번째 방법 : 쿼리 어노테이션 사용
@Repository
public interface BoardRepository extends JpaRepository<Board, Long> {
@Query("SELECT new com.yourpackage.BoardUserDTO(b.title, b.content, u.userName, u.userPhone) " +
"FROM Board b " +
"INNER JOIN b.user u " +
"WHERE u.seqNo = :userSeqNo")
List<BoardUserDTO> findByUserSeqNo(Long userSeqNo);
}
설명할 필요도 없다. 쿼리 어노테이션 사용 후 파라미터 값을 조건에 잘 매칭시키면 끝
장, 단점 결론
두 방법을 고려했을 때 굳이 이 개념들을 찾아가며 join에 대해 관리하기보단
mybatis에서 직관적으로 sql문을 작성하는 것이 규모 단위가 큰 프로젝트에서는 이점이 있다.
하지만
프로젝트를 처음 만들 때 JPA를 사용하겠다..!라는 것부터 이미 규모 산정이 이루어졌을 때의 이야기이기 때문에 “아.. JPA여서 개발이 힘드네?”라는 말은 나오지 않을 것으로 예상한다..
실무자 입장에서의 장점이 있다면 !
- SI 업무를 하는 개발자 입장에서 프로젝트 세팅부터 개발까지 빠르다.
- SI 개발을 마치고 납품 이후 사내에서 유지 보수까지 맡게 된다면 좀 더 빠르게 인수인계가 가능하다.
사용 방법
그렇다면 JPA를 프로젝트에 적용시키려면 어떻게 해야 할까
1. 의존성 추가
// build.gradle
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
2. 엔티티 등록
@Entity
@Table(name = "tbl_board")
public class Board {
3. 인터페이스 생성
import org.springframework.data.jpa.repository.JpaRepository;
public interface UserRepository extends JpaRepository<User, Long> {
}
4. 사용
private final UserRepository userRepository;
public List<User> getAllUsers() {
return userRepository.findAll();
}
마무리하며
규모가 큰 프로젝트는 애초에 프로젝트 리더가 JPA를 사용하자고 말도 꺼내지 않을 것이며
만약 규모가 크더라도, 테이블 JOIN 이 많지 않거나, DTO 활용, 어노테이션을 적절하게 잘 사용한다면
큰 단점이 없는 것 같다.
또한 처음 개발을 접하는 사람에게도 굳이 SQL문 오타 하나 나서 boardMapper.xml 파일 찾아가서
수정해서 다시 실행할바에 JPA가 직관적일지도 모른다.
초보부터 고수까지 모두에게 사랑받을 것 같은 JPA..
개발자로서 오랫동안 볼 것 같은 녀석이라서 한번 알아봤다.
'스프링' 카테고리의 다른 글
[SPRING] 왜 학교나 학원에서 MVC 패턴을 항상 공부할까? (1) | 2024.11.16 |
---|---|
[인텔리제이] 프로젝트 세팅이 귀찮을 때 꿀팁 방출 : 프로젝트 복사 쉽게하는 법 (1) | 2024.10.16 |
[Spring Boot -5] 스프링 부트가 개발자에게 직접적으로 주는 장점[3] root-context.xml (0) | 2024.04.11 |
[Spring Boot -4] 스프링 부트가 개발자에게 직접적으로 주는 장점[2] servlet-context.xml (0) | 2024.04.05 |
[Spring Boot -3]스프링 부트가 개발자에게 직접적으로 주는 장점[1] Web.xml (0) | 2024.03.27 |