(1) JPA 소개
2021. 6. 21. 09:50ㆍ개발공부/JPA 스터디
728x90
회사에서 Mybatis를 사용해 빚어지는 SQL 휴먼에러와 유지보수에 대한 어려움 때문에 JPA를 공부해 도입시키고자 스터디를 시작했습니다. 현재 5명인 스터디는 정해진 순서대로 맡은 챕터를 스터디 시간에 발표하는 방식으로 진행되고 있습니다. 요약본은 마크다운 파일로 Github 레포지토리에 커밋하기 때문에 같은 양식을 유지합니다.
JPA
장점
- CRUD SQL 작성할 필요가 없습니다.
- 성능에 대한 문제는 SQL을 직접 작성하는 것으로 보완할 수 있습니다. 네이티브 SQL로 직접 작성할 수도 있고 쿼리 힌트도 작성할 수 있습니다.
- 객체 중심으로 생산성과 유지보수가 확연히 좋아집니다. e.g. MySQL 데이터베이스에서 오라클 데이터베이스로 변경할 때 어렵지 않습니다.
SQL을 직접 작성할 때 발생하는 문제
DB구조는 객체 구조와는 다른 데이터 중심의 구조를 가지므로 개발자가 객체 지향 애플리케이션과 DB 중간에서 SQL과 JDBC API를 사용해 변환해줘야 합니다.
문제
- DB에 CRUD 하려면 많은 SQL과 JDBC API를 코드(or DAO 클래스)로 작성해야 합니다.
- 데이터 접근 계층(DAO)를 활용해서 SQL을 숨겨도 문제가 발생하면 어쩔 수 없이 어떤 SQL이 실행되는지 확인해야 한다는 점입니다.
- 갑자기 DB 테이블에 컬럼을 추가해달라는 요청이 왔을 때 SQL, DTO(Entity; 비즈니스 요구사항을 모델링한 객체), DAO를 수정해야 합니다. 하지만 자바 컬렉션에 보관했다면 필드를 추가해도 약간의 코드만 수정하면 됩니다.
- 진정한 의미의 계층분할은 SQL까지 확인하지 않고 데이터 접근 계층 또는 엔티티 계층에서 문제를 해결할 수 있어야 합니다.
요약
- 진정한 의미의 계층분할이 어렵다.
- 엔티티를 신뢰할 수 없다.
- SQL에 의존적인 개발을 피하기 어렵다.
JPA와 문제해결
직접 SQL을 작성하지 않고 JPA API를 사용합니다.
jpa.persist(member); //저장
jpa.find(Member.class, memberId); //조회
member.setName("이름변경"); //수정
Team team = member.getTeam(); //연관된 객체 조회
- 저장 : 이 메서드는 객체와 매핑정보(어떤 테이블에 관리할지 정의한 정보)를 보고 적절한 INSERT SQL을 생성해서 DB에 전달합니다.
- 수정 : 별도의 수정 메서드를 제공하지 않고 객체를 조회해서 변경만 해주면 트랜잭션을 커밋할 때 DB에 적절한 UPDATE SQL이 전달됩니다.(작동원리는 3장에서 설명)
- 연관된 객체 조회 : 연관된 객체를 사용하는 시점에 적절한 SELECT SQL을 실행합니다.(8장에서 설명)
패러다임의 불일치
- 비즈니스 요구사항을 정의한 도메인 모델도 객체로 모델링하면 객체지향 언어가 가진 장점들을 활용할 수 있습니다.
- 객체는 속성(필드)와 기능(메서드)를 가집니다.
- 객체가 단순하면 모든 속성 값을 DB에 저장하면 되지만, 부모 객체를 상속받았거나 다른 객체를 참조하고 있다면 객체의 상태를 저장하기 쉽지 않습니다. (e.g. 회원 객체가 팀 객체를 참조하고 있다면, 회원 객체를 저장할 때 팀 객체도 함께 저장해야 합니다.)
- Java는 이러한 문제를 고려해서 직렬화(;직렬화(直列化) 또는 시리얼라이제이션(serialization)은 컴퓨터 과학의 데이터 스토리지 문맥에서 데이터 구조나 오브젝트 상태를 동일하거나 다른 컴퓨터 환경에 저장(이를테면 파일이나 메모리 버퍼에서, 또는 네트워크 연결 링크 간 전송)하고 나중에 재구성할 수 있는 포맷으로 변환 ...)와 역직렬화를 고려합니다. 하지만 직렬화된 객체를 검색하기 어렵기 때문에 현실성이 없습니다. 대안은 RDB에 객체를 저장하는 것인데, 데이터 중심으로 구조화되어 있기 때문에 추상화, 상속, 다형성 같은 개념이 없습니다.
- DB와 객체의 패러다임 차이를 개발자가 해결하는 데 너무 많은 시간과 코드를 소비합니다.상속
- 이러한 ITEM을 부모로 가진 상속구조 객체를 DB에 저장하거나 조회하려면 각 클래스 단위로 SQL을 작성해야 하기에 코드량이 만만치 않습니다.
- JPA를 사용하면 find() 메서드를 사용해서 객체를 조회하면 됩니다. 참 쉽쥬?
String albumId = "id100";
Album album = jpa.find(Album.class, albumId);
SELECT I.*, A.*
FROM ITEM I
JOIN ALBUM A ON I.ITEM_ID = A.ITEM_ID
- JPA는 ITEM과 ALBUM 두 테이블을 조인해서 필요한 데이터를 조회하고 그 결과를 반환합니다.
연관관계
- 객체는 참조를 사용해서 다른 객체와 연관관계를 가지고 DB는 외래키를 사용합니다.
class Member {
Team team;
...
Team getTeam() {
return team;
}
class Team {
...
}
member.getTeam(); //member -> team 접근
}
SELECT M.*, T.*
FROM MEMBER M
JOIN TEAM T ON M.TEAM_ID = T.TEAM_ID
- 또한 객체는 참조가 있는 방향으로만 조회할 수 있지만 DB는 외래키 하나로 테이블끼리 양방향 JOIN이 가능합니다.
class Member {
String id; //MEMBER_ID
Long teamId; //TEAM_ID (FK)
String username; //USERNAME
}
class Team {
Long id; //TEAM_ID (PK)
String name; //NAME
}
- 외래 키까지 DB에 맞추면 객체가 참조하는 방식을 잃게되며 객체지향의 특징을 잃어버리게 됩니다.
- 객체지향 모델링
class Member {
String id; //MEMBER_ID
Team team; //참조로 연관관계를 맺는다
String username; //USERNAME
}
class Team {
Long id; //TEAM_ID (PK)
String name; //NAME
}
객체는 참조를 통해 연관관계를 맺고 DB 테이블은 외래키를 통해 연관관계를 맺기 때문에 각각 참조와 외래키를 가질 수 있도록 개발자가 변환해주는 역할을 해야합니다.
저장
- 객체를 DB에 저장하려면 team 필드를 teamId로 바꿔 INSERT 해줘야 합니다. member.getTeam.getId()로 구할 수 있습니다.
조회 - TEAM_ID 외래 키 값을 Member 객체의 team 참조로 변환해서 보관해야 합니다. 먼저 SQL문으로 MEMBER, TEAM을 조회해야 합니다.
- 이러한 과정들을 패러다임 불일치를 해결하려 소모하는 비용입니다. JPA는 연관관계와 관련된 패러다임의 불일치를 해결해줍니다.
JPA와 연관관계
member.setTeam(team);
jpa.persist(member); //insert
- JPA는 참조를 외래 키로 변환해서 적절한 SQL을 DB에 전달해줍니다.
- 반대로 조회할 때 외래 키를 참조로 변환하는 것도 JPA가 해결해줍니다.
- 복잡한 패러다임 불일치
- Member - Team 뿐만 아니라 Member - Order - OrderItem - Item - Category 처럼 복잡한 연관관계가 있을 때, SQL을 직접 입력하면 객체 그래프를 어디까지 탐색할 수 있는지 정해집니다.
- 하지만 모든 SQL을 적어둬야 하는건 번거로울 뿐더러 DAO가 SQL에 의존적인 코가 됩니다.
- JPA와 객체 그래프 탐색
- JPA는 연관된 객체를 사용하는 시점에 적절한 SQL을 실행합니다. 이기능은 사용시점까지 DB 조회를 미룬다고 하여 지연로딩이라 합니다.
비교
- 동일성(identity) vs 동등성(equals())
- DB는 기본 키의 값으로 로우를 구분합니다. 반면 객체는 동일성과 동등성 비교라는 두 가지 비교방법이 있습니다.
- 객체 측면에서 SQL을 실행한 결과값 인스턴스의 동일성이 다르지만 JPA는 같은 트랜잭션일 때 같은 객체가 조회되는 것을 보장합니다.
정리
- Java와 DB의 객체구조와 데이터 구조 패러다임 차이는 결국 데이터 중심으로 변해가게 됐습니다. 자바 진영에서 이러한 패러다임 불일치 문제를 해결하고 정교한 객체 모델링을 유지 하기위해 JPA를 만들어 낸 것입니다.
JPA 소개
- find(id) 메서드가 실행될 때 JPA가 하는 일 :
- SQL문 생성, JDBC API 사용, ResultSet 매핑, 패러다임 불일치 해결
- 자바 진영에는 패러다임 불일치 문제를 해결해주는 성숙한 ORM 프레임워크 하이버네이트가 있습니다.
- Java ORM 기술에 대한 API 표준이 바로 JPA이며 쉽게 말해 인터페이스를 모아둔 것입니다. 따라서 JPA를 사용하려면 구현한 ORM 프레임워크를 선택해야 하며 그 중 가장 대중적인 게 하이버네이트 입니다.
JPA 장점
- 생산성 : SQL을 일일이 작성하지 않아도 됩니다. DB 설계 중심 패러다임을 객체 설계 중심으로 역전시킬 수 있습니다.
- 유지보수 : SQL을 직접 다루면 엔티티 필드에만 수정이 있어도 JDBC API 코드를 모두 변경해야 했습니다. 하지만 JPA가 이런 과정을 처리해주기 때문에 수정할 코드가 줄어듭니다.
- 패러다임의 불일치 해결 : 상속, 연관관계, 객체 그래프, 비교하기와 같이 패러다임 불일치를 해결해주는 기능을 제공합니다.
- 성능 : DB와 애플리케이션 중간에서 같은 트랜잭션 안에서 두 번 조회하는 코드가 있을 때 SELECT SQL을 한 번만 DB에 전달하고 두 벉는 조회한 회원 객체를 재사용합니다.
- 데이터 접근 추상화와 벤더(MySQL, MariaDB...etc) 독립성 :
참고자료: 자바 ORM 표준 JPA 프로그래밍 (김영한 저)
'개발공부 > JPA 스터디' 카테고리의 다른 글
[ORM 표준 JPA] 14장 컬렉션과 부가기능 (0) | 2021.08.30 |
---|---|
[ORM 표준 JPA] 15장 프록시 심화 (0) | 2021.08.30 |
[실무 JPA] 엔티티 생성 (2) | 2021.08.04 |
[ORM 표준 JPA] 10장 객체지향 쿼리언어(JPQL) (1) (0) | 2021.07.25 |
(2) JPA 시작 (0) | 2021.06.21 |