소개 - SQL 중심적인 개발의 문제

14527 단어 JPAJPA

참고

도입

과거에 우리의 애플리케이션은 객체지향언어(Java, Scala, ...)로 만들어져있었고, 그렇게 많이들 운영을 해왔다.
그리고 DB쪽에서는 RDB(MySQL, Oracle, MariaDB, PostgreSQL), NoSQL, File등
여러가지가 있었지만 그중에서 RDB를 사용자들이 많이 사용하기 시작했다. 그리고 어느덧 데이터를 저장해서
운영하는 애플리케이션이 트렌트가 되게 되었고 우리 객체를 DB에 저장하자는 생각이 나오게 되었다.
그리고 현재는 이런 코드로 짠 객체를 RDB에 관리를 하는 시대가 오게 되었다. 하지만 여기서 문제사항이 발생하게 되었다. 바로, 앞전 포스트에서 이야기 했듯이 우리가 SQL을 일일이 type safe하지 못하게 적어야 하는 문제사항이 발생하게 되었다.

SQL 중심적인 개발의 문제점

  • 무한 반복, 지루한 코드
    • CRUD
    • INSERT INTO...
    • UPDATE...
    • SELECT...
    • DELETE...
    • 자바 객체를 SQL로..
    • SQL을 자바 객체로...
  • 객체 CRUD
public class Member {
  private String memberId;
  private String name;
   ...
}
INSERT INTO MEMBER(MEMBER_ID, NAME) VALUES 
SELECT MEMBER_ID, NAME FROM MEMBER M
UPDATE MEMBER SET ...
  • 객체 CRUD 필드 추가시,
    우리가 위와 같이 객체를 만들고 쿼리도 작성을 하였다. 하지만 갑자기 PM분이
    컬럼을 추가해달라는 상황이 올때 어떻게 대처를 해야하는가?
    당연히, 자바에 속성을 추가해주고 작성했던 sql문에 추가된 속성을 넣어줘야 하는 상황이 발생한다.
    결국, 객체지향적으로 코드를 작성할 시, SQL에 의존적인 개발을 피하기는 어렵다.

패러다임의 불일치 (객체 vs RDB)

그러면 여기서 잠시 들수 있는 생각이, SQL에 의존적인 개발을 하지말고, 그냥 절차지향으로 짜면 안될까?
상관은 없지만, 객체지향의 수 많은 이점을 포기하게되는 셈이다.

‘객체 지향 프로그래밍은 추상화, 캡슐화, 정보은닉, 상속, 다형성 등 시스템의 복잡성을 제어할 수 있는
다양한 장치들을 제공한다.
form. 어느 객체지향 개발자

그럼 객체지향은 유지하되, RDB를 사용하지 말고 다른 DB를 사용하면 어떨까?

위의 이미지처럼 객체를 영구보관하는 DB는 RDB를 말고도 다른 DB들도 있지만, 결론은 RDB가 우리가 사용하기에 편하고
다른거에 비해 쉽게 사용도 가능하다.

ex. File로 예를 들면 수많은 객체를 File로 저장하면 용량이 어마어마해지며 감당이 안될것 같다.

결국, 현실적인 대안은 관계형 데이터베이스이다.

그럼 객체를 관계형 데이터베이스에 저장을 할려면 어떤 공정이 들어갈까?

위의 사진처럼 객체를 SQL로 변환하는 converter가 존재해야한다. 그럼 이 converter는 누가 해주는가?
바로 SQL Mapper나 개발자 본인이 직접해야한다. 정말 어마무시한 공정일것이다.

그럼 어떤 차이점이 있길래 객체를 SQL로 변환작업을 해줘야하는가?

  • 상속
  • 연관관계
  • 데이터 타입
  • 데이터 식별 방법

위와 같은 곳에서 차이점을 발견할 수 있다.

상속

상속같은 경우에는 아래 그림처럼 객체는 상속관계가 존재하지만 SQL은 그 비스무리한 것이 존재하지만
너무 비효율적인 부분으로 없다고해도 무방할것이다.

예를 들면 Book을 저장하려고 하면, Insert query문을 item테이블과 book테이블 2군데에 다 해줘야하는 비효율적인 부분이 있다. 또한, book 조회시, 각각의 테이블에 따른 조인 SQL문을 작성해야하며, 각각의 객체를 생성해서 그 데이터들을 넣어줘야한다. 즉, 이래서 DB에 저장할 객체에는 상속관계를 쓰지 않는다.

자바 컬렉션에 저장 및 조회할 경우는 어떤가?

Book book = list.get(bookId);

Item item = list.get(bookId);

위처럼 간단하게 사용이 가능하며, 부모타입으로 조회 후, 다형성까지 활용이 가능하다.

연관관계

  • 객체는 참조를 사용 : member.getTeam(); (단방향 참조)
  • 테이블은 외래 키를 사용 JOIN ON M.TEAM_ID = T.TEAM_ID (양방향 참조)

모델링

우리가 일반적인 모델링을 할 때, DB 테이블을 보고 모델링을 진행한다. 예시로는 아래와 같다.

class Member {
  String id; //MEMBER_ID 컬럼 사용
  Long teamId; //TEAM_ID FK 컬럼 사용 //**
  String username;//USERNAME 컬럼 사용
}
class Team {
  Long id; //TEAM_ID PK 사용
  String name; //NAME 컬럼 사용
}

여기서 뭔가 좀 더 객체다워질려면

class Member {
  String id; //MEMBER_ID 컬럼 사용
  Team team; // 참조로 연관관계를 맺는다.//**
  String username;//USERNAME 컬럼 사용
  
  Team getTema() {
  	return team;
  }
}
class Team {
  Long id; //TEAM_ID PK 사용
  String name; //NAME 컬럼 사용
}

여기서 SQL로 변환할때 Team부분은 member.getTeam().getId()로 team_id를 찾아 변환해서 넣어야한다.

여기서 조회를 할 때, 다음과 같이 이루어질수 있다.

SELECT M.*, T.* FROM MEMBER M
JOIN TEAM T ON M.TEAM_ID = T.TEAM_ID
public Member find(String memberId) {
  //SQL 실행 ...
  Member member = new Member();
  //데이터베이스에서 조회한 회원 관련 정보를 모두 입력
  Team team = new Team();
  //데이터베이스에서 조회한 팀 관련 정보를 모두 입력
  //회원과 팀 관계 설정
  member.setTeam(team); //**
  return member;
}

객체 그래프 탐색

객체는 자유롭게 객체 그래프를 탐색할 수 있어야 한다.

탐색이라는 의미는 객체의 체이닝메소드로 접근이 가능해야한다.

하지만 처음 실행하는 SQL에 따라 탐색 범위가 결정된다.

SELECT M.*, T.* FROM MEMBER M
JOIN TEAM T ON M.TEAM_ID = T.TEAM_ID
member.getTeam(); //OK 
member.getOrder(); //null

여기서 member.getOrder()가 null인 이유는 sql 조회할때 order 테이블은 조회하지 않았기 때문이다.

또한 엔티티 신뢰문제도 발생할 수 있다.

class MemberService {
...
  public void process() {
  Member member = memberDAO.find(memberId);
  member.getTeam(); //???
  member.getOrder().getDelivery(); // ???
  }
}

여기서 membetDAO.find() 메소드에서 어떤 쿼리가 발생했는지 확인해봐야 하는 귀찮음이 있다.
그래서 getTeam(), getOrder().getDelicery()가 null인지 아닌지를 이 코드만 보고 확인할 수 없다.

그러면 아예 모든 객체를 미리 로딩하면 안될까?

먼저 정답은 그럴수 없다. 상황에 따라 동일한 회원조회 메서드를 여러벌 생성하는 방법이 유일하다.

memberDAO.getMember(); //Member만 조회 

memberDAO.getMemberWithTeam();//Member와 Team 조회
 
//Member,Order,Delivery
memberDAO.getMemberWithOrderWithDelivery();

즉, 진정한 의미의 계층 분할은 어렵다. 또한, 객체답게 모델링 할수록 매핑 작업만 늘어난다.
그럼 여기서 이 문제들을 해결할수 없을까?
또한 객체를 자바 컬렉션에 저장 하듯이 DB에 저장할 수는 없을까?

해결방안은 JPA가 키를 가지고 있다. JPA에 관련된 사항은 다음 포스트에 게시하도록 하겠다.

마무리

나는 이 강의 듣기 전에 JPA사용방법에 대해서만 아는데 급급했던것 같았는데 이래서 JPA가 도입이 되었고 왜 필요했는지를 이 강의를 듣고 많은 깨달음을 얻게 된 계기가 되었다.

좋은 웹페이지 즐겨찾기