
나는 JPA를 사용해본 적이 있기 때문에 얼마나 좋은 기술인가에 대해서는 직접 체감해봐서 잘 알고있다. 하지만 사용할줄만 알고 JPA가 정확히 어떤건지에 대해 제대로 설명할 수 없었다.
제대로 알지 못한채 살아가다 최근에 인프런 연말 할인을 보고 이때다 싶어, 너무나 듣고싶었던 김영한님의 JPA 강좌를 구매했다. 그리고 진행중인 프로젝트에 JPA를 적용할 예정이였기 때문에 너무나 좋은 기회였다.
아무튼... 이번 벨로그 시리즈는 김영한님의 강좌를 기반으로 글을 정리할 예정이다.
본격적으로 강의를 수강하기 전에 ORM이 등장하게된 배경을 10분 테크톡 - 아마찌의 ORM vs SQL Mapper vs JDBC 영상을 보면서 정리해보고자 한다.
Persistence는 한국어로 영속성이라 한다. 영속성은 데이터를 생성한 프로그램이 종료되더라도 사라지지 않는 데이터의 특성을 의미한다. 즉, 우리가 흔히 개발할 때 객체의 상태를 DB에 저장하게 되는데 이를 객체에 영속성을 부여해주었다고 말한다.
그리고 Mark Richards의 소프트웨어 아키텍처 패턴을 보면 Persistence Layer가 존재하는 것을 볼 수 있다. 이 계층은 객체에 영속성을 부여해주는 것을 의미한다.

이 Persistence Layer를 구현하는 방법은 크게 JDBC만을 이용하거나 Persistence Framework를 이용하는 방법이 있다.
JDBC(Java Database Connectivity)는 자바에서 데이터베이스에 접속할 수 있도록 도움을 주는 자바 API다. JDBC의 장점은 각각의 DBMS가 제공하는 JDBC 드라이버를 이용만한다면, DBMS의 종류와 상관없이 하나의 JDBC API를 이용하여 DB 작업을 처리할 수 있다는 것이다.

하지만 JDBC만을 이용하여 개발할 경우에는 불편한점이 꽤 많다.
그래서 이런 복잡하고 번거로운 작업을 해결하기 위해 데이터베이스와 연동되는 시스템을 빠르게 개발할 수 있는 Persistence Framework를 사용하기 시작한 것이다. (참고로 Persistence Framework는 모두 내부적으로 JDBC를 이용하고 있다!)
SQL Mapper는 SQL문과 객체를 매핑하여 데이터를 객체화하는 Persistence Framework다. 즉, 객체간의 관계를 매핑하는 것이 아닌 직접 작성한 SQL문의 결과와 객체의 필드를 매핑하는 것이 메인 컨셉이다.
영상에서는 JDBC, JDBC Template 그리고 MyBatis 예시를 비교하면서 보여주었다.



결국 SQL Mapper를 이용하면 기존에 JDBC만을 이용했을 때보다 코드가 간결해지고 유지보수성이 향상되는 효과를 보여준다는 것이다! 👏
하.지.만!
SQL Mapper가 JDBC만을 사용했을 때보다 많은 불편함을 해소해주었음에도 여전히 문제가 있다.
즉, 코드상에서는 SQL과 JDBC API를 분리했어도 논리적으로는 강한 의존성을 가지고 있게 되며 SQL에 의존적인 개발을 해야하는 문제가 발생한다.
또한 객체지향에는 "캡상추다"라는 특징을 가지고 있는 반면, RDB에서는 데이터 중심의 구조를 지니고 있기 때문에 패러다임 불일치가 생긴다. 따라서 객체지향적으로 개발할 수록 패러다임 불일치 문제는 강해지게 된다.
ORM은 패러다임 불일치 문제를 해소한 - 객체와 RDB를 매핑하는 기술이다. ORM은 객체간의 관계들을 바탕으로 SQL문을 자동으로 생성하고 직관적으로 데이터를 조작하게하여 개발자의 불편함을 해소한다.
ORM의 대표적인 기술은 바로 JPA가 있다. (여기서부터는 강좌의 내용도 가져와보자. 😀)
원래 JPA 기술이 나오기 전까지는 EJB(Entity Bean)이라는 자바 표준 기술이 있었다. 하지만 워낙 복잡하다보니 Gavin King이라는 개발자가 하이버네이트라는 오픈 소스를 만들어냈고, 그러다 자바 진영에서 Gavin King을 데려와 하이버네이트 기반으로 자바 표준인 JPA를 만들어냈다고 한다.

추후에 다시 정리할 예정이지만 간단하게 동작 과정을 살펴보자.



JPA에서는 같은 트랜잭션 안에서는 같은 엔티티를 반환한다. 예를 들어 조회 쿼리를 보내고 결과를 받아올 때, 처음에 받아온 결과를 캐시해두어서 사용하게 된다는 의미다. 따라서 JPA로 같은 트랜잭션 내에서 동일한 조회 코드를 두 번 작성했음에도 단 하나의 쿼리가 전송된다.
쓰기 지연 기능은 트랜잭션을 커밋할 때까지 INSERT 쿼리문을 모아두는 기능을 의미한다. JDBC BATCH SQL 기능을 이용하면 한번에 SQL을 전송할 수 있다. 따라서 쓰기 지연 기능을 이용하면 한번에 쿼리문을 모았다가 보내기 때문에 네트워크 통신 비용이 절감되는 장점이 있다.
JPA에서는 지연 로딩과 즉시 로딩 기능을 제공해준다. 지연 로딩은 객체가 사용될 때 로딩하는 것을 의미하고, 즉시 로딩은 JOIN SQL로 한번에 연관된 객체까지 미리 조회하는 것을 의미한다. 지연 로딩과 즉시 로딩을 시기적절하게 잘 활용만 한다면 성능 최적화에도 큰 이점을 가질 수 있다.
지연 로딩에 대한 예시는 다음과 같다.
Team team = member.getTeam();
String teamName = team.getName(); // 실제로 사용될 때 로딩