JDBC (Java DataBase Connectivity)
Java Code + SQL 존재. => 유지 보수 및 확장성 문제가 있음 (SQL 이 혼자 일 다해서..)
SQL Mapper
Java Code 와 SQL 을 완전 분리.
sql 서비스별로 관리가 가능해지므로, 응집도가 높아지면서 재사용성이 높아졌음.
=> SQL 코드 품질 향상, SQL 성능 향상으로 이어짐.
MyBatis SQL 관리 파일
- 서비를 위한 SQL (응집도 향상 목적)
- SQL Mapper 로 SQL 을 분리해서 관리할 수 있으나, 그래도 SQL 을 사용하면서 관리해야 하는 불편함이 있음.
A. ORM의 장점
- SQL을 직접 작성하지 않고, 사용하는 개발 언어로 데이터베이스에 접근할 수 있음,
- 객체지향적으로 코드를 작성할 수 있기 때문에 비즈니스 로직에 집중할 수 있음.
- 데이터베이스 시스템이 추상화되어 있기 때문에 H2와
다른 데이터베이스로 변경되더라도 추가로 필요한 작업이 들지 않음.
=> 데이터베이스에 대한 종속성이 감소 (ORM을 사용하는 이유)
B. ORM의 단점
- 프로젝트의 복잡성이 커질수록 사용 난이도가 올라감.
- 복잡하고 무거운 쿼리는 ORM으로 해결이 불가능 할 수도 있음
- SQL 에 직접적인 튜닝이 어려움.
A. Entity - @Entity 사용
A.1 Entity Manager (엔터티 매니저, EM)
A.2 엔터티 관리 상태
1. 분리 상태
2. 관리(영속) 상태
3. 비영속 상태
4. 삭제된 상태
1. 1차 캐쉬
- 엔터티를 조회를 하는 경우, 1차 캐쉬에서 데이터를 조회한 후, 값이 존재할 경우 반환하고, 없으면 DB에서 조회한 후에 1차 캐쉬에 저장 후 반환한다.
2. 쓰기 지연
- 쓰기 지연은 트랜잭션을 커밋하기 전까지는 데이터베이스에 실제로 질의문을 보내지 않고, 쿼리를 모아두었다가 트랜잭션을 커밋하면 모아두었던 쿼리를 한꺼번에 실행하는 것을 의미함.
따라서, 적당한 묶음으로 쿼리를 요청할 수 있기 때문에 Data Base의 부하를 줄일 수 있음.
3. 변경 감지
- 트랜잭션을 커밋하면 1차 캐쉬에 저장되어 있는 엔터티의 값과 현재 엔터티의 값을 비교한 후, 변경된 값이 있다면 변경 사항을 감지해 변경된 값을 DataBase에 자동 반영함.
따라서, 쓰기 지연처럼 적당한 묶음으로 쿼리를 요청할 수 있고, DataBase에 대한 부하를 낮출 수 있게 됨.
4. 지연 로딩 (테이블간의 관계성이 있는 경우)
- 지연 로딩(lazy loading)은 쿼리로 요청한 데이터를 애플리케이션에 바로 로딩하는 것이 아니라, 필요할 때 쿼리를 보내서 데이터를 조회하는 것을 의미함.
+ 반대의 경우 : 즉시 로딩
- 즉시 로딩은 조회할 때 쿼리를 보내 연관된 모든 데이터를 가져오는 것을 의미함.
공통점
- 모든 데이터베이스의 접근을 최소화해서 성능을 높일 수 있도록 하는 점.
캐쉬를 하거나, 자주 쓰지 않게 하거나, 변화를 자동 감지해서 미리 준비하거나 하는 등의 방법을 이용
결론- JPA 를 사용하려면, 반드시 상기의 특징을 이해하고 사용할 수 있도록 해야 함.
- 엔터티를 영구 저장하는 환경
member 를 관리하는 경우의 영속 컨텍스트의 1차 캐쉬의 모양.
@id entity snapshot
'member1' member1 entity member1 entity 원본 <=> DB
'member2' member2 entity member2 entity 원본 <=> DB
snapshot 항목은 entity 의 update 상태 유무를 판단하기 위한 것임.
( 변경 감지 용 )
Member a = em.find('member1');
Member b = em.find('member1');
System.out.println( a == b );
=> 동일성 비교시, 결과는 항상 true! 따라서 영속성 컨텍스트는 항상 동일성을 보장함.
getById() : 검색한다는 의미보다는 가져온다는 의미가 있음.
해당되는 엔터티가 없으면 예외가 발생함.
findById() : 검색한다는 의미가 있음.
실제 DB에 요청해서 엔터티를 가져옴.
영속성 컨텍스트의 1차 캐쉬에 먼저 확인 후, 엔터티가 없으면
실제 DB에 데이터가 있는지 확인함.
결과적으로 entity가 있거나, 없으면, null 이 발생함.
모든 필드를 대상으로 Update를 수행.
이유) 애플리케이션 로딩 시점에 update sql 을 미리 생성해 두고 재사용이 가능할 수 있음.
데이터베이스에 동일한 SQL을 전송하면 데이터베이스는 이전에 한 번 파싱된 SQL을 재사용할 수 있게 됨.
삭제의 경우도 바로 삭제가 되는 것이 아니라, 쓰기 지연 SQL 저장소에 SQL이 저장된 후, 트랜잭션이 커밋해서 엔터티 매니저의 flush() 가 호출되면 실제 데이터베이스에 delete sql을 전달하게 됨.
영속성 컨텍스트의 변경 내용을 데이터베이스에 반영하는 기능.
변경감지가 동작해서 영속성 컨텍스트에 있는 모든 엔터티를 스냅샷과 비교해서 수정이 발생된 엔터티를 찾음. 수정된 엔터티는 update query 를 만들어서 쓰기 지연 SQL 저장소에 저장.
쓰기 지연 SQL 저장소의 쿼리가 데이터베이스에 전송(insert, update, delete)
영속성 컨텍스트틀 flush 하는 방법
>1. entity manager의 flush() 호출
2. 트랜잭션 커밋시 flush() 가 자동 호출
3. JPQL 쿼리 실행 시 자동으로 flush() 가 호출