배경
iBatis, MyBatis 혹은 Spring JDBC Template 같은 SQL Mapper를 사용하면, CRUD 용 SQL은 반복해서 작성해야 한다.
-> 비생산적이다.
JPA는 반복적인 CRUD SQL을 알아서 처리해주고, 객체 모델링과 관계형 데이터베이스 사이의 차이점도 해결해준다.
실행시점에 자동으로 SQL을 만들어서 실행하는데, JPA 사용자는 SQL을 직접 작성하는 것이 아니라 어떤 SQL이 실행될지 생각만 하면 된다.
즉, 정리하면
- CRUD SQL을 작성할 필요가 없다.
- 조회된 결과를 객체로 매핑하는 작업을 대부분 자동으로 처리해준다.
- 애플리케이션을 SQL이 아닌 객체 중심으로 개발하니 생산성과 유지보수가 좋아진다.
- 데이터베이스를 변경( ex. MySQL -> Oracle )하여도 코드를 거의 수정하지 않아도 된다.
SQL을 직접 다룰 때 발생하는 문제점
예시로 회원 관리 기능을 만들어본다고 가정하자.
회원 객체
public class Member {
private String memberId;
private String name;
}
회원용 DAO
public class MemberDAO {
public Member find(String memberId) {}
}
find() 메소드를 완성하기 위해 코드를 추가해보자
- 회원 조회용 SQL 작성
select member_id, name from member m where member_id = ? - JDBC API를 사용하여 SQL 실행
ResultSet rs = stmt.executeQuery(sql); - 조회 결과를 Member 객체로 매핑
String memberId = rs.getString("member_id");
String name = rs.getString("name");
Member member = new Member();
member.setMemberId(memberId);
member.setName(name);
이렇게 조회기능을 작성하고 등록, 수정, 삭제하는 기능을 추가하려면 아마도 SQL을 작성하고 JDBC API를 사용하는 비슷한 일을 반복해야한다.
데이터베이스는 객체 구조와는 다른 데이터 중심의 구조를 가지므로 객체를 데이터베이스에 직접 저장하거나 조회할 수 없다.
앞에서 MemberDAO의 CRUD 기능을 완성하였다고 가정해보자.
그런데 갑자기 회원의 연락처도 함께 저장해달라는 요구사항이 추가되었다고 가정하자.
그럼 회원 테이블에 tel 컬럼을 추가하고 회원 객체에 tel 필드를 추가해야한다.
즉, 회원 클래스에 연락처(tel) 필드를 추가하고, insert SQL문을 수정해야한다.
String sql = "insert into member(member_id, name, tel) values(?, ?, ?)";
조회 코드도 변경해야한다.
기존의 코드로 조회하면 모든 연락처의 값이 null로 출력된다.
따라서, 회원 조회용 SQL을 수정해야한다.
마찬가지로 수정 기능도 변경해야한다.
회원은 어떤 한 팀에 필수적으로 소속되어야 한다는 요구사항이 추가되었다고 가정하자.
회원 클래스에 연관된 팀 추가
public class Member {
private String memberId;
private String name;
private String tel;
private Team team;
}
public class Team {
private Long teamId;
private String teamName;
}
MemberDAO에 회원을 출력할 때 사용하는 find() 메소드는 회원만 조회하는 SQL을 그대로 유지하고,
findWithTeam() 메소드를 만들어 SQL로 회원과 연관된 팀을 함께 조회하였다.
select m.member_id, m.name, m.tel, t.team_id, t.team_name
from member m
join team t
on m.team_id = t.team_id
SQL과 문제점을 정리해보자
Member 객체와 Team 객체를 사용할 수 있을지 없을지는 전적으로 SQL에 달려 있다.
이런 방식의 문제점은 데이터 접근 계층을 사용해서 SQL을 숨겨도 어쩔 수 없이 DAO를 열어서 어떤 SQL이 실행되는지 무조건 확인해야 한다.
Member나 Team처럼 비즈니스 요구사항을 모델링한 객체를 엔티티라고 하는데, 지금 처럼 SQL에 모든 것을 의존하는 상황에서는 개발자들이 엔티티를 신뢰하고 사용할 수 없다.
또한, 물리적으로는 SQL과 JDBC API를 데이터 접근 계층에 숨기는 데 성공했을지는 몰라도 논리적으로는 엔티티와 아주 강한 의존관계를 가지고 있다.
이러한 문제 때문에 회원을 조회할 때는 물론이고 회원 객체에 필드를 추가할 때도 DAO의 CRUD 코드와 SQL 대부분을 변경해야 하는 문제가 발생한다.
이러한 문제점을 요약하면
- 진정한 의미의 계층 분할이 어렵다.
- 엔티티를 신뢰할 수 없다.
- SQL에 의존적인 개발을 피하기 어렵다.
JPA 기능 예시
- 저장 기능
jpa.persist(member);
persist() 메소드는 객체를 데이터베이스에 저장한다.
이 메소드를 호출하면 JPA가 객체와 매핑정보를 보고 적잘한 insert SQL을 생성해서 데이터베이스에 전달한다. - 조회 기능
String memberId = "memberId";
Member member = jpa.find(Member.class, memberId);
find() 메소드는 객체 하나를 데이터베이스에서 조회한다.
JPA는 객체와 매핑정보를 보고 적절한 select SQL을 생성해서 데이터베이스 전달하고 그 결과로 객체를 반환한다.
'Spring JPA' 카테고리의 다른 글
영속성 관리 - 6 (0) | 2021.06.29 |
---|---|
영속성 관리 - 5 (0) | 2021.06.26 |
JPA 시작 - 4 (0) | 2021.06.25 |
JPA 소개 - 3 (0) | 2021.06.23 |
JPA 소개 - 2 (0) | 2021.06.22 |
댓글