Reference. 자바 ORM 표준 JPA 프로그래밍
책 목차 및 이전 글
더보기
들어가기 전 JPA 특징, Q&A
1. JPA 소개
3. 영속성 관리
4. 엔티티 매핑
4.1 - 4.3 @Entity, @Table, 다양한 매핑
4.4 - 4.5 데이터베이스 스키마 자동 생성, DDL 생성 기능
5. 연관관계 매핑 기초
6. 다양한 연관관계 매핑
7. 고급매핑
8. 프록시와 연관관계 관리
9. 값 타입
9.3~5 값 타입과 불변 객체, 값 비교, 값 타입 컬렉션
10. 객체지향 쿼리 언어
11. 웹 애플리케이션 제작
11.1 프로젝트 환경설정
11.2 도메인 모델과 테이블 설계
11.3 애플리케이션 구현
12. 스프링 데이터 JPA
12.1~3 스프링 데이터 JPA 소개, 공통 인터페이스 기능
12.5~10 명세, 사용자 정의 리포지토리, Web 확장...
13. 웹 애플리케이션과 영속성 관리
14. 컬렉션과 부가기능
15. 고급 주제와 성능 최적화
- 영속성 컨텍스트 내부에는 인스턴스 보관소인 1차 캐시가 존재
- 1차 캐시는 영속성 컨텍스트와 생명주기가 같음
- 1차 캐시의 가장 큰 장점은 애플리케이션 수준의 반복 가능한 읽기가 가능
- 같은 영속성 컨텍스트에서 엔티티를 조회하면 항상 같은 엔티티 인스턴스를 반환
- 동등성(equals) 비교 수준이 아닌 정말 주소값이 같은 인스턴스를 반환
Member member1 = em.find(Member.class, "1L"); Member member2 = em.find(Member.class, "1L"); assertTrue(member1 == member2); //둘은 같은 인스턴스
15.2.1 영속성 컨텍스트가 같을 때 엔티티 비교
- 테스트와 트랜잭션 범위 예제 코드
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(loacations = "classpath:appConfig.xml") @Transactional //트랜잭션 안에서 테스트를 실행 public class MemberServiceTest { @Autowired MemberService memberService; @Autowired MemberRepository memberRepository; @Test public void 회원가입() throws Exception { //Given Member member = new Member("kim"); //When Long saveId = memberService.join(member); //Then Member findMember = memberRepository.findOne(saveId); assertTrue(member == findMember); //참조 값 비교 } @Transactional public class MemberService { @Autowired MemberRepository memberRepository; public Long join(Member member) { ... memberRepository.save(member); return member.getId(); } } @Repository public class MemberRepository { @PersistenceContext EntityManger em; public void save(Member member) { em.persist(member); } public Member findOne(Long id) { return em.find(Member.class, id); } } }
- 테스트 클래스에
@Transactional
이 있으면 트랜잭션을 먼저 시작하고 테스트 메소드 실행
회원가입()
은 트랜잭션 범위에 있으므로 메소드가 끝나면 트랜잭션이 종료, 메소드에 사용된 코드는 항상 같은 트랜잭션과 영속성 컨텍스트에 접근
- 저장한 회원과 회원 리포지토리에서 찾아온 엔티티가 완전히 같은 인스턴스
Member member = new Member("kim"); Long saveId = memberService.join(member); Member findMember = memberRepository.findOne(saveId); assertTrue(member == findMember); //참조값 비교
- 같은 트랜잭션 범위에 있으므로 같은 영속성 컨텍스트를 사용하기 떄문에 동일
- 테스트 클래스에
- 영속성 컨텍스트가 같으면 엔티티를 비교할 때 3가지 조건을 모두 만족
동일성(identical)
: == 비교가 같음
동등성(equinalent)
: equals() 비교가 같음
데이터베이스 동등성
: @Id인 데이터베이스 식별자가 같음
15.2.2 영속성 컨텍스트가 다를 때 엔티티 비교
- 영속성 컨텍스트가 다를 때 엔티티 비교 예제 코드
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(loacations = "classpath:appConfig.xml") //@Transactional //테스트에서 트랜잭션을 사용하지 않음 public class MemberServiceTest { @Autowired MemberService memberService; @Autowired MemberRepository memberRepository; @Test public void 회원가입() throws Exception { //Given Member member = new Member("kim"); //When Long saveId = memberService.join(member); //Then Member findMember = memberRepository.findOne(saveId); assertTrue(member == findMember); //참조 값 비교 } @Transactional //서비스 클래스에서 트랜잭션이 시작 public class MemberService { @Autowired MemberRepository memberRepository; public Long join(Member member) { ... memberRepository.save(member); return member.getId(); } } @Repository @Transactional //예제를 구성하기 위해 추가 public class MemberRepository { @PersistenceContext EntityManger em; public void save(Member member) { em.persist(member); } public Member findOne(Long id) { return em.find(Member.class, id); } } }
- 테스트는 실패하며 그 이유는 영속성 컨텍스트의 생존 범위 때문에 발생
- 테스트 코드에서
memberService.join(member)
를 호출하면 서비스 계층에 트랜잭션이 시작되고 영속성 컨텍스트1이 생성
memberRepository
에서em.persist()
를 호출해서 member 엔티티를 영속화
- 서비스 계층이 끝날 때 트랜잭션이 커밋되면서 영속성 컨텍스트가 플러시 처리하며 이때 트랜잭션과 영속성 컨텍스트가 종료, 따라서 member 엔티티 인스턴스는 준영속 상태
- 테스트 코드에서
memberRepository.findOne(saveId)
를 호출해서 저장한 엔티티를 조회하면 리포지토리 계층에 새로운 트랜잭션이 시작되면서 영속성 컨텍스트2가 생성
- 저장된 회원을 조회하지만 새로 생성된 영속성 컨텍스트2에는 찾는 회원이 없음
- 데이터베이스에서 회원을 조회
- 데이터베이스에서 조회된 회원 엔티티를 영속성 컨텍스트에 보관하고 반환
memberRepository.findOne()
가 끝나면 트랜잭션이 종료되고 영속성 컨텍스트2도 종료
- member와 findMember는 각각 다른 영속성 컨텍스트에서 관리되어 다른 인스턴스
assertTrue(member == findMember); //실패
- member와 findMember는 인스턴스는 다르지만 같은 DB로우를 조회, 사실상 같은 엔티티
동일성(identical)
: == 비교가 실패
동등성(equinalent)
: equals() 비교가 같음, 단 equals()를 구현필요 보통 비즈니스 키로 구현
데이터베이스 동등성
: @Id인 데이터베이스 식별자가 같음
- 이 경우
euqlas()
로 동등성 비교 사용, 엔티티를 비교할 떄 비즈니스 키를 활용한 비교를 권장- 만약 주민등록번호가 있다면 좋은 비즈니스 키 대상
- 또는 회원 엔티티에 이름과 연락처가 같은 회원이 없다면 조합해서 사용도 가능
'개발서적 > 자바 ORM 표준 JPA' 카테고리의 다른 글
[자바 ORM 표준 JPA 프로그래밍] 15.4 성능 최적화 (0) | 2021.10.25 |
---|---|
[자바 ORM 표준 JPA 프로그래밍] 15.3 프록시 심화 주제 (0) | 2021.10.25 |
[자바 ORM 표준 JPA 프로그래밍] 15.1 예외 처리 (0) | 2021.10.25 |
[자바 ORM 표준 JPA 프로그래밍] 14.4 엔티티 그래프 (0) | 2021.10.25 |
[자바 ORM 표준 JPA 프로그래밍] 14.3 리스너 (0) | 2021.10.25 |