이번에는 JPA (Java Persistence API)에 대해 알아보려고 한다.
기존에는 JPA를 사용하지 않고 SQL문을 직접 작성하여 개발했었다. JPA는 기존에 SQL 중심적인 개발에서 객체 중심으로 개발할 수 있게 사용하는 프레임워크이다. 즉, JPA는 자바 진영에서 ORM (Object-Relational Mapping) 기술 표준으로 사용되는 인터페이스의 모음이다.
그렇다면, JPA에서 Persistence는 무슨 의미이고, 또 ORM 은 무엇일까?
우선 Persistence부터 알아보도록 하자.
Persistence는 JPA에서 "영속성"이라는 의미로 사용된다.
JPA에는 영속성 컨텍스트 라는 개념이 존재하는데 JPA를 이해하는데 가장 중요한 용어이다.
영속성 컨텍스트는 "엔티티를 영구 저장하는 환경"이라는 뜻이다.
일단 JPA라는 개념은 "데이터를 영속성있게 관리해 주는 API"라고 이해하였다.
다음은 ORM에 대해 알아보도록 하자.
여태까지 내가 Java로 DB를 조작해 온 방법은 SQL Mapper였다.
ORM은 직접 DB를 조작하는 SQL Mapper와 다르게 간접적으로 DB를 조작하는 방법을 사용한다.
이 둘의 차이점에 대해 알아보자.
SQL Mapper
- Object와 SQL의 필드를 매핑하여 데이터를 객체화하는 기술이다.
- Mapper 방식을 사용한다면 중복되는 코드들을 줄일 수 있다.
- SQL문을 직접 작성하고 쿼리 수행결과를 어떠한 객체에 줄 지 바인딩하는 방법
- ex) JdbcTemplate, Mybatis
문제점
- 비슷한 SQL문이 여전히 존재한다.
- 테이블의 필드가 추가되거나 삭제될 경우 이와 관련된 모든 DAO의 SQL문, 객체의 필드 등을 수정해야 한다.
- SQL에 의존적인 개발을 피하기 어렵다.
- 객체답게 모델링할수록 매핑 작업만 늘어난다
이런 문제점들과 "객체를 자바 컬렉션에 저장하듯이 DB에 저장할 수는 없을까?"라는 의문에
나온 것이 ORM 방식이다.
ORM (Object - Relational Mapping)
- Object와 DB테이블을 매핑하여 데이터를 객체화하는 기술
- 객체는 객체대로 설계, 관계형 데이터베이스는 관계형 데이터베이스대로 설계한다.
- ORM 프레임워크가 중간에서 매핑한다.
- 대중적인 언어에는 대부분 ORM 기술이 존재한다.
- ex) Hibernate, JPA, Spring-Data-JPA
장점
- SQL 중심적인 개발에서 객체 중심으로 개발이 가능하다.
- 필드 변경 시 기존 모든 SQL 수정을 해야 했던 SQL Mapper 방식과 다르게 필드만 변경하면 된다.
=> 유지보수가 쉽다. - 성능 최적화
- 1차 캐시와 동일성 보장 : 같은 트랜잭션 안에서는 같은 엔티티를 반환한다. => 약간의 조회 성능 향상
- 트랜잭션을 지원하는 쓰기 지연
- 지연 로딩 : 객체가 실제 사용될 때 로딩
단점
- 프로젝트가 복잡해질수록 어려움이 있다.
- 복잡한 SQL의 경우 개발자가 직접 추가해야 한다.
JPA는 ORM 방식을 사용한다는 것, 직접 SQL 매핑하지 않는다는 것을 확인하였다.
JPA에 대해 더 알아보도록 하자.
JPA (Java Persistence API)
- Java 진영에서 ORM 기술 표준으로 사용하는 인터페이스 모음이다.
- JPA는 애플리케이션과 JDBC 사이에서 동작한다.
그렇다면 JPA를 왜 사용해야 할까?
이 질문에는 여러 가지의 답변이 있다.
먼저, "생산성" 측면이다.
기존 SQL Mapper에서 SQL문을 직접 작성하는 방법보다 JPA를 사용하면 훨씬 생산성 있는 개발을 할 수 있다.
JPA의 저장부터 조회, 수정, 삭제를 보자.
JPA 동작 - 저장
DB에 Member 데이터를 저장할 때, MemberDAO에서
jpa.persist(member);
이 문장만 작성해 주면 DB에 Member 데이터가 저장되는 것이다.
JPA 동작 - 조회
마찬가지로 DB에서 Member 데이터를 조회하려고 할 때,
Member member = jpa.find(memberId);
이 문장만 작성해 주면 Member 데이터가 조회가 되는 것이다.
JPA - 수정
JPA는 수정 메서드를 제공하지 않는다. 따라서 데이터 수정 시, 매핑된 객체(테이블 데이터)를 조회해서 값을 변경 후 커밋하면 UPDATE문이 실행하게 된다.
member.setName("변경할 이름");
JPA - 삭제
삭제할 때는
jpa.remove(member);
를 사용하면 되는 것이다.
JPA는 반복적인 CRUD SQL을 처리해 준다. JPA는 매핑된 관계를 이용해서 SQL을 생성하고 실행하는데, 개발자는 어떤 SQL이 실행될지 생각만 하면 되고, 예측도 쉽게 할 수 있다. 또한 생산성, 유지보수, 성능 측면에서 SQL Mapper 방식보다 유리하게 사용할 수 있다.
또한 JPA는 패러다임의 불일치도 해결하였다.
JAVA에서는 부모클래스와 자식클래스의 관계. 즉, 상속관계가 존재한다.
데이터베이스에서는 이러한 객체의 상속관계를 지원하지 않는다. 이런 상속관계를 JPA는 해결하였다.
이런 구조에서 만약 Album 클래스를 저장한다고 하자.
개발자는 아래의 코드를 작성할 것이다.
jpa.persist(album);
그러면 JPA는 위의 코드를 아래의 코드를 처리하는 것이다.
INSERT INTO ITEM (ID, NAME, PRICE) ...
INSERT INTO ALBUM (ARTIST) ...
Album 클래스를 조회할 때도 마찬가지이다.
개발자는 아래의 코드를 작성하는 것이 할 일이다.
Album album = jpa.find(Album.class, albumId);
그러면 나머지는 JPA가 처리하는 것이다.
SELECT I.*, A.*
FROM ITEM I
JOIN ALBUM A ON I.ITEM_ID = A.ITEM_ID
상속관계뿐만 아니라, 연관관계에서의 접근도 제공해 준다.
위의 구조는 Member 클래스가 Team 타입의 team 필드 변수를 가지고 있는 형태이다.
위와 같이 연관관계가 있는 구조에서 Member 객체를 저장한다고 하자.
개발자는 아래처럼 member 객체에 team객체를 set 하고 member 객체를 저장하는 코드를 작성하면 된다.
Member member = new Member();
member.setId("1");
member.setUserName("gang");
Team team = new Team();
team.setName("backend_team");
member.setTeam(team);
jpa.persist(member);
그러면 JPA는 아래의 코드를 데이터베이스에게 실행하라고 할 것이다.
INSERT INTO MEMBER (ID, TEAM_ID, USERNAME) ...
INSERT INTO TEAM (ID, NAME)...
조회할 때도 마찬가지이다.
개발자는 아래의 코드를 작성하고
Member member = jpa.find(Member.class, memberId);
Team team = member.getTeam();
나머지는 JPA가 처리하게 된다.
SELECT M.*, T.*
FROM MEMBER M
JOIN TEAM T ON M.TEAM_ID = T.TEAM_ID
위와 같은 구조들이 더 복잡해진다고 해도 JPA는 이를 모두 지원해 주기 때문에 문제없이 사용할 수 있는 것이다.
이번에는 JPA가 무엇인지, 왜 사용해야 하는지 알아보았다. 다음에는 JPA를 실제로 사용하여 개발하는 과정을 다루겠다.
참조
'Java' 카테고리의 다른 글
[SpringBoot] 이미지(파일) 저장 (0) | 2024.07.30 |
---|---|
[Java/Spring Boot] Java로 웹 크롤링 해보기 (Naver 날씨) (0) | 2023.02.22 |