[JPA] SQL중심 개발의 문제점
✔ SQL 중심적인 개발의 문제점
SQL을 작성해서 개발을 진행?
CRUD
INSERT INTO...
UPDATE...
SELECT...
DELETE...
자바 객체를 SQL로 표현...
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 ...
- 회원 테이블 생성 후, 회원 객체를 생성한다
- 기본 SQL 작업을 수행한다
- 기획자가 갑자기 요구사항을 변경한다
- 변경 되어야 하는 부분 - DB, 객체(Member)
SQL 의존적인 개발
- RDBMS를 사용하게 되면 SQL에 의존적인 개발을 피하기가 힘들다
Mybatis
- JDBC를 대체하는 퍼시스턴스 프레임워크로 기존 JDBC가 제공하던 불편한 부분을 보완해 나온 기술
- 개발자가 직접 SQL을 작성하여 세부적인 쿼리 조작이 가능하며, 비즈니스 로직과 SQL을 분리하여 레이어 구분이 가능
객체 vs 관계형 데이터베이스
- 패러다임의 불일치?
- 객체 지향이 나온 사상과, 관계형 데이터베이스가 나온 사상이 다르다
- 관계형 DB는 데이터를 잘 정규화하여 보관하는 목적
- 객체지향은 속성과 기능을 잘 캡슐화하여 쓰는 목적
- 객체 지향 프로그래밍은 추상화, 캡슐화, 정보은닉, 상속, 다형성 등
- 시스템의 복잡성을 제어할 수 있는 다양한 장치들을 제공한다
현실적인 대안은 관계형 DB?
- 객체 -> SQL 변환 -> SQL RDB
- 개발자 == SQL 매퍼 ( Mybatis, ibatis )
- 즉, 이말은 개발자가 관여해야하는 부분이 많아진다는 의미
- SQL을 반복적으로 직접 작성하여 RDB와의 데이터 수/송신을 해야함
✔ 객체와 관계형 데이터베이스의 차이
상속
- 객체
- 객체에는 상속 관계가 존재
- DB
- DB에는 상속 관계가 존재하지 않음, 굳이 정의 하자면 Super type, Sub Type
연관관계
- 객체
- 객체에는 연관관계가 존재 ( 연관 객체를 참조하여 가져온다 )
- DB
- DB에는 PK, FK를 통해 데이터 조인
- 데이터타입
- 데이터 식별 방법
자바 컬렉션에 저장?
Album album = list.get(albumId);
Item item = list.get(albumId);
- 만약 자바 컬렉션에 저장을 한다고 하면, 해당 컬렉션에 넣었다, 뺏다만 해주면 된다
- 또한 다형성을 이용하여 부모 타입으로 자식 타입의 객체를 받을 수 있다
- 관계형 DB 사용 시 개발자가 SQL을 작성해서 모든 부분을 관리
연관관계
--------------------------------------------------
객체
Member Team
id id
Team team -> name
userName
테이블
MEMBER TEAM
MEMEBER_ID (PK) TEAM_ID (PK)
TEAMP_ID (FK) NAME
USERNAME
--------------------------------------------------
- 객체는 참조를 사용
- member.getTeam();
- 테이블은 외래키를 사용
- JOIN IN M.TEAM_ID = T.TEAM_ID
- Member 객체 -> Team 객체 ( o )
- Team 객체 -> Member 객체 ( x )
- MEMBER 테이블 -> TEAM 테이블 ( o )
- TEAM 테이블 -> MEMBER 테이블 ( o )
- 객체는 단방향, 테이블을 양방향
객체 모델링, 자바 컬렉션에 관리?
list.add(member);
Member member = list.get(memberId);
Team team = member.getTeam();
- 추상화
- SuperMember > Member > Team
객체 그래프 탐색
SELECT M.*, T.*
FROM MEMBER M
JOIN TEAM T ON M.TEAM_ID = T.TEAM_ID
- 객체는 자유롭게 객체 그래프를 탐색할 수 있어야 한다 ( 메서드 체이닝 )
- 처음 실행하는 SQL에 따라 탐색 범위가 결정됨
- 즉, 이 말은 MEMBER랑 TEAM 테이블만 조인을 하였기에 범위가 2개로 좁혀진다
- ORDER 테이블에서 데이터를 가져오려면 조인을 또 추가해야 한다
객체 그래프 탐색 - 엔티티 신뢰 문제
class MemberService {
...
public void process() {
Member member = memberDao.find(memberId);
member.getTeam();
member.getOrder().getDelivery();
}
}
- memberDao에서 member객체를 반환해주네?
- Team, order객체를 반환 받아볼까?
- memberDao에 맵핑된 쿼리를 직접 보지 않는 이상 신뢰할 수없다
- Layered architecture 각 계층의 신뢰성이 보장 되어야 한다
- 하지만 현재는 DAO에서 어떤 행동(Action)을 했는지 일일이 까봐야 알 수 있음
엔티티 신뢰를 지키기 위한 방법
memberDao.getMember();
memberDao.getMemberWithTeam();
//Member, Order, Delivery
memberDao.getMemberWithOrderWithDelivery();
- 테이블마다 가져오고자 하는 값을 분리하여, 데이터를 가져온다
- 대부분 이런 방식으로 구분을 하여 데이터를 가져옴
- 실무에서도 결제 문서를 가져오는 SQL, 유저 정보를 가져오는 SQL을 각각 짜서 사용한다
계층형 아키텍처
- SQL을 통한 구현은 진정한 의미의 계층 분할( Layerd Arcitecture )가 어렵다.
비교하기
String memberId = "100";
Member member1 = memberDao.getMember(memberId);
Member member2 = memberDao.getMember(memberId);
member1 == member2; // 두 객체는 다르다
class MemberDao {
public Member getMember(String memberId) {
String sql = "SELECT * FROM MEMBER WHERE MEMBER_ID = ?";
...
// JDBC API, SQL 실행
return new Member(...);
}
}
- memeberId가 100인 데이터를 넣어서 member1, member2 객체를 반환 받는다
- 하지만 결과는 false가 나온다, 객체가 참조하고 있는 주소가 다르기 때문이다
- 이러한 부분을 통해 객체의 일관성이 보장되지 않음을 알 수 있다
비교하기 - 자바 컬렉션에서 조회
String memberId = "100";
Member member1 = list.get(memberId);
Member member2 = list.get(memberId);
member1 == member2;
- 참조값이 동일하게 나온다
문제점을 해결하기 위한 해결 방안
- 🚀
객체 지향적으로 설계를 하고 모델링을 할수록 매핑 작업이 늘어난다
- 🚀
객체를 자바 컬렉션에 저장 하듯이, DB에 저장할 수 없을까?
- 📌
이러한 고민의 결과가 JPA - Java Persistance API다
- 📌
댓글남기기