본문 바로가기

JPA

SQL 중심적인 개발의 문제점

지금 웹사이트의 99%는 객체를 통하여 관계형 DB를 관리한다고 해도 과언이 아니라고 생각한다.
이런 시대의 흐름 속에서 개발자들은 SQL 중심적인 개발을 피할 수 없었다.
왜냐하면 DB는 SQL밖에 알아듣지 못하기 때문이었다.
그렇다면 이 SQL중심적인 개발은 우리 개발자들에게 좋은 것이었을까?

 

SQL중심적인 개발의 문제점

1. 지루한 코드가 무한반복된다

뭘 만들든 자바 객체를 SQL로, SQL을 자바객체로 변환시키기 위해 코드에서는 CRUD를 위한 SQL이 무한반복된다.
다음과 같은 Member 클래스가 있다.

public class Member {
    private String memberId;
    private String pw;
    private String name;
    private String tel;
}

 

그리고 [로그인] [회원가입] [회원정보수정] 기능을 위해 SQL은 다음과 같이 만들 것이다.

insert into member(id, pw, name, tel) values()
select * from member where ...
update member set ...

이러한 틀은 게시판에서도 쇼핑몰 웹페이지에서도 반복된다. 벌써 힘들다.

2. 유지보수가 힘들다

위처럼 Member관련기능을 구현했는데, 기획이 변해서 mail도 저장해야 한다.

그렇다면 Member 클래스의 구조를 바꾸는 것은 물론이고 작성한 SQL마다 가서 mail컬럼 관련 작업을 해줘야 한다.

즉, VO의 수정으로 인해 Controller와 Model, SQL 등 코드의 전반적인 부분들을 수정해야 하는 것이다.
이는 아키텍쳐가 물리적으로는 분리되어 있지만, 논리적으로는 끈끈하게 연관되어 있다는 것을 뜻한다.

일이 고되지고, 점점 자신이 하는 것이 개발인지 SQL매핑인지 알 수가 없게 된다.

3. 패러다임의 불일치로 객체지향설계를 하면 DB작업이 고달파진다.

1. 상속: 쿼리와 코드가 복잡해져요

객체의 상속과 Table의  슈퍼타입  서브타입 관계

위와 같은 Table 사이에서 Album객체를 저장할 경우 Item과 Album Table에 insert하는 쿼리를 각각 작성해야 한다.
또한 Album 객체를 조회할 경우에도 Item과 Album Table을 Join하여 각각 객체에 값을 넣어줘야 한다.
이런 복잡한 상황을 방지하기 위해서 Entity에는 상속 관계를 사용하지 않게 된다.
하지만 DB가 아닌 자바 컬렉션에 저장하고 조회할 경우 매우 간단해진다. 뿐만 아니라 다형성 활용도 가능해진다.

// 컬렉션으로 저장
list.add(album);

// 컬렉션으로 조회
Album album = list.get(albumId);
// 부모타입으로 조회하여 다형성 활용도 가능
Item item = list.get(albumId);

2. 연관관계: 쿼리와 코드가 복잡해져요

객체는 참조를 사용: 단방향 ex) member.getTeam()

테이블은 키를 이용한 join을 사용: 양방향 ex) join on m.team_id=m.tema_id

 

 

위와 같은 Entity(Member, Team)에서 Member를 조회해보겠다.

Member member = memberDAO.find(memberId);
Team team = teamDAO.find(teamId);

//연관관계 설정
member.setTeam(team);

어떤 식으로 짜든 DB에서 찾아온 데이터를 member와 team 객체에 각각 저장한 후 연관관계 설정을 해주는 복잡하고도 귀찮은 틀을 벗어날 수 없다.

 

하지만 이것도 상속과 같이 DB가 아닌 자바 컬렉션에서 관리할 경우 매우 간단해진다.

list.add(Member);

Member member = list.get(memberId);
Team team = member.getTeam();

3. 객체 그래프 탐색: 지키는 것이 불가능해요

객체는 자유롭게 객체 그래프를 탐색할 수 있어야 하는데

이런 객체 그래프에서 우리는 Order나 Team을 Member Entity에서 자유롭게 가져올 수 없다.

왜냐하면 Order와 Team이 있고 없고는 실행한 SQL의 탐색범위에 따라서 달라지기때문이다.

select * from member m inner join team t on m.team_id = t.team_id;

위와 같은 SQL문으로 Member를 조회하고 연관관계를 설정했을 경우 Team객체는 문제가 없겠지만, Order객체에는 null값이 저장되게 된다. 따라서 객체는 자유롭게 그래프를 탐색할 수 없고, 더 크게 본다면 엔티티를 신뢰할 수 없게 된다. 대응책으로 아래와 같이 회원조회 메서드를 룰에 맞춰 여러 개 만들게 된다.

public interface MemberDAO {
    public Member getMember();
    public Member getMemberWithTeam();
    public Member getMemberWithOrderWithDelivery();
}

그나마도 완벽한 것이 아닌 개발자들끼리 약속하고 쓸 뿐인 것이다. 완벽하지 않은 이유는 객체가 자유롭게 그래프를 탐색할 수 없는 것은 여전하기때문이다.


4. DB와 JAVA Collection

이 부분은 패러다임의 불일치보다는 데이터를 컬렉션이 관리하는 것과 DB가 관리하는 것의 차이를 볼 수 있다.

100번 멤버를 DB에서 얻어와서 비교할 때 ==연산자를 사용하면 false가 반환되고, list에서는 true가 반환된다.

같은 멤버임에도 DB에서 조회하여 비교한 결과는 false이다.

이러한 부분뿐만 아니라 JAVA Collection은 많은 장점을 가지고 있고, Collection처럼 DB를 관리하는 방법을 연구하게 된다.

 

// DB의 데이터 관리
String memberId = "100";
Member member1 = memberDAO.getMember(memberId);
Member member2 = memberDAO.getMember(memberId);

System.out.println(member1 == member2); //false
// 컬렉션의 데이터 관리
String memberId = "100";
Member member1 = list.get(memberId);
Member member2 = list.get(memberId);

System.out.println(member1==member2); //true

그래서 결국 개발자들은 객체답게 모델링하려고 하면 할수록 고통받았고, 
객체를 자바 컬렉션에 저장하듯이 DB에 저장하는 방법을 연구했고, 그 고민의 끝에서 JPA가 탄생한다.

 

참고강의: 배달의 민족 개발팀장 김영한 강사님의 JPA 강의