JPA를 사용하는 이유

Posted by sJun on November 01, 2020 ·

보통 DB를 연동하는 방법은 여러가지가 있습니다.

그 중 우리나라 SI 업체에서 실무에서 가장 많이 쓰는 프레임워크는 당연히 MyBatis 라고 할 수 있습니다.

MyBatis 가 분명히 파라미터 값도 자동으로 넣어주는 등등..

여러가지로 편한 것은 사실이지만 결국 SQL 쿼리문은 반복적으로 작성해야 된다는 것이 단점입니다.

    <select id="findMemberById" resultType="Member">
        SELECT id
              ,name
              ,price
        FROM Member
        WHERE id = #{memberId}
    </select>

    <select id="findAllMember" resultType="Member">
        SELECT id
              ,name
              ,price
        FROM Member
    </select>

    <insert id="insertMember" parameterType="Member">
      INSERT INTO members (name, price)
      VALUES (#{name}, #{price})
    </insert>

대충 작성한 MemberMapper.xml 파일입니다.

위의 코드만 보면 참 간단해보이지만 프로젝트가 커지면 커질수록 위의 SQL 구문 또한 엄청나게 증가합니다.

그리고 개인 프로젝트만 하더라도 수시로 기능이 바뀌거나 하는데 그럴 때마다 또 SQL을 수정해야합니다. 연관된 것 전부다요.

두번째로는 객체의 상속 관계와 테이블의 슈퍼타입 - 서브타입의 관계는 비슷한거 같지만 상당히 다릅니다.

일단 테이블의 슈퍼타입 - 서브타입은 FK와 PK로 구분 한다는 점이지만 자바는 그런 것이 없다는게 차이죠.

vip

위의 클래스를보면 Member 클래스를 상속 받는

VIP 고객 클래스와 Normal 고객 클래스가 있습니다.

자바 컬렉션에 저장하려면 단순히

list.add(vip);

만 해주면 끝이지만 SQL 같은 경우는 상속 객체를 하나씩 전부 분해해서 저장해야합니다.

INSERT INTO MEMBER ...
INSERT INTO VIP ...

조회는 또 어떻게 해야할까요?

각각의 테이블에 대해서 조인 SQL을 또 작성하고 다시 각각의 객체를 생성합니다.

여기서부터 지옥같은 SQL 복붙 시작

그래서 DB에 저장할 객체에는 상속 관계를 안쓰긴 합니다만..

어쨌든 이러한 문제들 때문에 SQL 의존적인 코드는 엔티티 자체에 대해 신뢰성이 깨져버리게 됩니다.

    class Member{
        String id;
        VIP vip; // 참조
        string username;

        ...
    }

예를 들어서 Member 내부에 VIP라는 객체를 선언했다고 칩시다.

아이디값을 얻기 위해서 자바 같은경우는 객체 인스턴스를 만들어서 member.getVIP().getId() 이런 식으로 꺼내오기만 하면됩니다.

하지만 DB 같은 경우는 다릅니다.

예를 하나 들겠습니다.

SELECT M. *, V. * FROM MEMBER M JOiN VIP V ON M.ID = V.ID

조인 후

// SQL 실행
Member member = new Member();
// 회원 관련 정보 입력
VIP vip = new VIP(); 
// DB에서 조회한 VIP 정보 입력

member.setRole(vip);
// Member의 Role 결정
return member;
INSERT INTO MEMBER(MEMBER_ID, VIP_ID, USERNAME) VALUES ...()

이런 식으로 진행된다고 가정합시다.

vip2

그리고 위의 그림처럼 주문과 배송 정보를 멤버와 연관 시켰습니다

(사실 진짜 연관시키려면 Order나 VIP의 reference를 Member에도 넣어줘야 정확하지만 예제니까 간단하게 넘어갈게요)

자 그럼 여기서

member.getOrder()

가 먹힐까요?

당연히 안됩니다 우리는 위의 SQL 쿼리문에서 이미 탐색범위를 정했습니다.

단순히 VIP에 대해서만 말이죠

여기서 DB와 객체의 차이는 객체는 이어져 있기만 하면 어디로든지 갈수 있는 반면에 DB은 그렇지 않다는 점입니다.

즉 내가 Member 필드안에 Order 객체가 들어있다 한들 값을 마음대로 가져올 수가 없다는 점입니다.

class MemberService(){
    public void A(){
        Member member = memberDao.find(memberId);
        member.getRole();
        member.getOrder.getDelivery();
    }
}

단순히 위 코드만 보면 getDelivery를 확실하게 가져올지 신뢰가 다소 떨어집니다. 확인하려면 결국 SQL 구문을 또 확인해봐야겠죠

결론


정리하면 개발자는 정말 객체 지향의 원리에 입각해서 코드를 짰는데 이게 DB랑 연동 하려고보니 해야할 매핑 작업만 늘어난다는 것입니다.

위의 Order와 Delivery 객체를 불러오려면 다시 Mapper.xml에 가서 귀찮은 SQL 작성을 또 해줘야 됩니다. 기능이 바뀌면? 다시 SQL 쿼리문을 전면 수정해야합니다.

그래서 객체를 자바 컬렉션의 기능처럼 DB에 저장하고 꺼내올 수는 없을까가 JPA의 탄생 원인이 되었습니다.