DB에서는 데이터를 관리하기 위해 SQL을 사용해야 한다. Java의 경우 JDBC API를 이용하여 SQL을 DB에 전달한다.

다음과 같은 예시 상황을 살펴보자.
예시로 다음과 같이 Member객체를 만들고
public class Member {
private String memberId;
private Stirng name;
}
public class MemberDAO {
public Member find(String memberId) {...}
public void save(Member member) {...}
}
SELECT member_id, name FROM member WHERE member_id = ?
String sql = "INSERT INTO member(member_id, name) VALUES(?, ?)";
ResultSet rs = stmt.executeQuery(sql);
pstmt.setString(1, member.getMemberId());
pstmt.setString(2, member.getName());
String memberId = rs.getString("member_id");
String name = rs.getString("name");
Member member = new Member();
member.setMemberId(memberId);
member.setName(name);
pstmt.executeUpdate(sql);
데이터베이스는 객체 구조와 다른 데이터 중시므이 구조를 가지므로 객체를 데이터베이스에 직접 저장하거나 조회할 수 없어 SQL과 JDBC API를 사용하여 변환 작업을 해야한다. 이러한 과정은 반복적인 작업을 요구하고 많은 SQL과 JDBC API를 코드로 작성해야한다.
또한 개발과정에서 코드를 수정하는 일은 불가피하게 자주 발생하게 되는데 코드를 수정하게 될 경우 이러한 문제점과 추가 문제점 들이 발생하게된다.
요약해 보자면 애플리케이션에서 SQL을 직접 다루게 될 경우 진정한 의미의 계층 분할이 어려워지고 엔터티를 신뢰할 수 없게 되며 SLQ에 의존적인 개발을 피하기 어렵게 된다.
위 문제들은 JPA를 이용하여 해결 가능하다!
JPA를 사용하게 되면 객체를 DB에 저장하고 관리할 떄 개발자가 직접 SQL을 작성하지 않고 JPA가 제공하는 API를 사용하면 된다.
애플리케이션은 Java라는 객체지향 언어로 개발하고 데이터는 관계형 데이터베이스에 저장해야 한다면 패러다임의 불일치 문제를 개발자가 직접 해결해 줘야한다. 이러한 불일치 문제는 해결할 수 있지만 많은 시간과 많은 코드들이 필요하다.
첫번째로 상속이다.

우측은 객체 상속 모델이고 좌측은 테이블 모델이다. 객체는 상속이라는 기능이 있지만 테이블은 상송이라는 기능이 없다. 가장 유사하게 슈퍼타입-서브타입 관계를 사용하여 설계할 수 있다. JDBC API를 사용하여 구현할려면 갱신, 수정, 삭제 모두 쉽지 않고 번거롭다.
이러한 점을 JPA는 쉽게 해결할 수 있다. 개발자는 자바 collection에 객체를 저장하듯이 JPA에게 객체를 저장하면된다.
객체 저장의 경우 presist()메소드를 사용해서 객체를 저장한다.
객체 조희의 경우 find()메소드를 사용해서 객체를 조회한다.
member.setTeam(team); //회원과 팀 관계 설정
jpa.persist(member); //회원과 연관관계 함께 저장
Member member = jpa.find(Member.class, memberId);
Team team = member.getTeam();
다음과 같이 JPA를 활용하여 참조를 외래키로 변환해 적절한 SQL문을 DB로 전달하며 조회 시 외래키를 참조 변환하는 일 역시 가능하다.
member.getOrder().getOrderItem()...//자유로운 객체 그래프 탐색
JPA를 활용하면 다음과 같이 적절한 SQL문을 실행하여 자유롭게 조회할 수 있다. 이러한 위의 기능을 Lazy Loading이라고 한다.
String memeberId = "100";
Member member1 = memberDAO.getMember(memberId);
Member member2 = memberDAO.getMember(memberId);
member1 == member2; // false
Member member1 = list.get(0);
Member member2 = list.get(1);
member1 == member2; // true
DB는 기본키의 값으로 각 row를 구분하지만 객체는 동일성비교와 동등성 비교라는 두가지 비교 방법이 있다.
테이블 과 객체는 구분(비교)하는 방법에 차이가 존재한다.
🕯️동일성 비교 vs 동등성 비교
- 동일성 비교는 == 비교 -> 객체 인스턴스의 주소 값을 비교
- 동등성 비교는 equals() 비교 -> 객체 내부의 값을 비교
String memberId = "100";
Member member1 = jpa.find(Member.class, memberId);
Member member2 = jpa.find(Member.class, memberId);
member1 == member2; // true
JPAf를 활용하면 같은 트랜잭션일 댸 같은 객체가 조회되는 것을 보장할 수 있다.
JPA는 Java진영의 ORM 기술 표준으로 아래 그림과 같이 동작한다.
🕯️ORM
- 객체와 관계형 데이터베이스를 메핑한다는 것
- ORM 프레임워크 사용 시 객체와 테이블을 매핑해서 페러다임의 불일치 문제를 개발자 대신 해결


jpa.persist(member);
세부적으로 살펴보면 JPA에게 Member객체를 넘기면 JPA가 객체를 분석하고 INSERT 쿼리가 생성된다(JPA가 만듬). JPA가 JDBC API를 사용하여 INSERT 쿼리를 DB에 보내게 되며 패러다임의 불일치를 해소한다.

Member member = jpa.find(memberId);
세부적으로 살펴보면 JPA에게 PK값으로 find요청을 보내고 JPA는 SELECT 쿼리를 생성한다. JPA가 JDBC API를 사용하여 DB에 보내고 결과를 받아온다. 이를 ResultSet에 매핑하여 패러다임의 불일치를 해소한다.
JPA를 사용하기 위해서는 JPA를 구현한 ORM 프레임워크를 선택해서 사용해야한다. ORM프레임워크 종류에는 하이버네이트(Hibernate), EclipseLink, DataNucleus가 있는데 하이버네이트가 가장 대중적이다.
JPA를 사용하는 이유는 대표적으로 생산성, 유지보수, 패러다임의 불일치 해결, 성능, 데이터 접근 추상화와 벤더 독립성, 표준이 있다.
생산성 - CURD모두 정의되어 있다.
🕯️JPA CRUD 살펴보기
저장: jpa.persist(member)
조회: Member member = jpa.find(memberId)
수정: member.setName(“변경할 이름”)
삭제: jpa.remove(member)
유지보수 - 필드 변경시 모든 SQL 수정해야 했으나 JPA사용시 필드만 추가하면 된다.
패러다임의 불일치 해결 - 앞에 내용에서 확인해봄(상속, 연관관계, 객체 그래프탐색, 비교)
성능 - JPA는 애플리케이션과 DB사이에서 성능 최적화 기회를 제공한다.
데이터 접근 추상화와 벤더 독립성 - ??
표준 - Java의 ORM 기술 표준이다.
유익한 글 잘 읽었습니다.🙂
오늘도 힘내세요.🙌🙌🏻🙌🏼