본문 바로가기

스프링

[SPRING] JPA는 현업에서 많이 쓰일까 ?

반응형
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여서 개발이 힘드네?”라는 말은 나오지 않을 것으로 예상한다..

실무자 입장에서의 장점이 있다면 !

  1. SI 업무를 하는 개발자 입장에서 프로젝트 세팅부터 개발까지 빠르다.
  2. 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..

 

개발자로서 오랫동안 볼 것 같은 녀석이라서 한번 알아봤다.

반응형