ultra_dev
JPA 기본 본문
기존 방식
:
객체를 관계형 DB에 관리한다는 것 이 문제
→ 개발자가 객체로 데이터를 가공했지만 DB에 저장할 땐 결국 SQL → SQL 중심적인 개발이 되버린다.
❓ 무엇이 문제인가?
- 기능하나 추가해서 테이블이 생성 될 때마다 CRUD SQL을 다 만들어줘야 한다.
기존 회원객체와 테이블 기능쿼리 구현
/*회원 객체*/
public class Member {
private String memberId;
private String name;
}
/*쿼리*/
INSERT INTO MEMBER(MEMBER_ID, NAME) VALUES ...
SELECT MEMBER_ID, NAME FROM MEMBER M
UPDATE MEMBER SET ...
기획자가 전화번호 필드를 추가 해 달라고 한 상황
/*회원 객체*/
public class Member {
private String memberId;
private String name;
private String tel;
}
/*쿼리*/
INSERT INTO MEMBER(MEMBER_ID, NAME, TEL) VALUES ...
SELECT MEMBER_ID, NAME, TEL FROM MEMBER M
UPDATE MEMBER SET ...TEL = ?
- 모든 CRUD 쿼리에 TEL을 하나하나 추가해줘야 한다.
결론: SQL에 의존적인 개발을 할 수밖에 없다.
- 객체를 SQL로 변환해서 RDB에 저장하는 변환과정을 개발자가 해야 한다.
- → 노가다 시작
이런 문제를 해결하기 위해 나온 것이 JPA
자바 ORM 진영의 표준.
객체와 테이블을 매핑해서 패러다임의 불일치를 개발자 대신 해결해준다.
- JPA를 자바 컬렉션에 객체를 저장하듯 JPA에게 저장할 객체를 전달.
- INSERT SQL을 작성하고 JDBC API 사용하는 지루하고 반복적인 일을 JPA가 대신 처리해준다.
- CREATE TABLE같은 DDL문 자동 생성
- 데이터베이스 설계 중심의 패러다임을 객체 설계 중심으로 역전
- 상속, 연관관계, 객체 그래프 탐색, 비교하기 같은 패러다임 불일치 해결
+ JPA는 특정 데이터베이스에 종속되지 않는다
- ex) 가변문자: mysql은 varchar, oracle은 varchar2
- ex) 문자열 가르는 함수 : sql 표준은 substring(), oracle은 substr()
- ex) 페이징 : mysql은 limit, oracle은 rownum
- 이런 방언(sql 표준 지키지 않는 특정 데이터베이스만의 고유기능)에 종속되지 않음
영속성 컨텍스트란?
- 엔티티를 영구 저장하는 환경
- EntityManager.persist(entity); → 좀 더 풀어서 설명하면 DB에 저장한다기보다는 영속성 컨텍스트를 통해 엔티티를 영속화 한다는 의미
- 영속성 컨텍스트에 엔티티를 저장한다는 말
- 영속성 컨텍스트는 논리적인 개념.
- 눈에 보이지 않는다.
- 엔티티 매니저를 통해서 영속성 컨텍스트에 접근
- 비영속(new/ transient)
- → 영속성 컨텍스트와 전혀 관계가 없는 새로운 상태
- 영속(managed)
- → 영속성 컨텍스트에 관리되는 상태
- 준영속(detached)
- → 영속성 컨텍스트에 저장되었다가 분리된 상태
- 삭제(removed)
- → 삭제된 상태
- EntityManagerFactory는 애플리케이션 로딩 시점에 딱 1개만 만듦 → 웹서버 올라오는 시점에 db당 1개만 생성!
- EntityManager : 실제 db에 저장하는 트랜잭션 단위!! 디비 커넥션 얻어서 쿼리 날리고 종료되는 한 일관적인 단위할 때마다 EntitiyManager 만들어줘야함 🐥 → 고객 요청올 때마다 만들어진다고 보면 됨
- 엔티티매니저는 쓰레드간에 공유 X!!!!! (사용하고 바로 버려야됨) 만들고 버리고 만들고 버리고~ 데이터베이스 커넥션 빨리 쓰고 돌려주는 것마냥
- 지연로딩: 객체가 사용될 때 로딩
Member member = memberDAO.find(memberId); //SELECT * FROM MEMBER
Team team = member.getTeam();
String teamName = team.getName(); //SELECT * FROM TEAM
- 즉시로딩: JOIN SQL로 한번에 연관된 객체까지 미리 조회
Member member = memberDAO.find(memberId); // SELECT M.*, T.* F FROM MEMBER JOIN TEAM...
Team team = member.getTeam();
String teamName = team.getName();
- jpa 작동 순서
- jpa 트랜잭션 커밋 호출 ( commit() 메소드)
- jpa 엔티티 매니저 내부에서 플러시**(flush()**) 발생. 이때 변경된 엔티티들이 쓰기 지연 저장소로 이동
- jpa는 플러시 이후 더티 체킹 수행. 변경된 엔티티들과 영속성 컨텍스트에 저장된 원본 엔티티 비교하여 변경 사항 감지
- 변경된 엔티티들의 변경 사항을 쓰기 지연 저장소에 모음
- 쓰기 지연 저장소에 있는 쿼리들이 데이터베이스에 일괄적으로 보내짐
- 트랜잭션 커밋**(commit)** 완료되면 쓰기 지연 저장소에 보관된 변경 사항들이 한번에 데이터 베이스에 반영됨
- 롤백시 쓰기지연저장소에 보관된 변경사항들도 롤백됨
- 조심 : 데이터베이스에 보내는거랑 반영이랑은 다름!! 보내고 커밋완료돼야 반영되는 것!!
'SPRING&JAVA' 카테고리의 다른 글
View Table + JPA 매핑 (0) | 2023.11.06 |
---|---|
Schema 여정기 Multi-Tenancy(feat. PostgreSQL) (0) | 2023.11.01 |
체크 예외, 언체크 예외 (0) | 2023.05.27 |
배열 <깊은 복사, 얕은 복사> (0) | 2023.01.13 |
(pathVariable/QueryParameter)//(AccessToken,RefreshToken) (0) | 2023.01.12 |
Comments