728x90
지난 과제를 어느 정도 마무리하면서 추가로 궁금했던 내용들을 정리해보려고 한다.
JPA에서는 엔티티 매니저에 의해 엔티티들을 영속화시켜 주는데, Spirng data JPA의 경우 내부적으로 처리해주다보니 오히려 영속화나 트랜잭션 과정에 대해 이해가 잘 되지 않았다.
그래서 영속성 컨텍스트에 대해 더 공부할 필요성을 느꼈다.
Spring Security 필터에서 받아온 User 엔티티는 영속화되어 있지 않다
- 엔티티의 변화가 일어나는 곳은 반드시 트랜잭션이 필요하다
- DB 상에 엔티티 데이터의 변화를 반영하기 위해서 !
- 스프링 시큐리티 컨텍스트에서의 JPA 엔티티는 준영속 상태
- 스프링 시큐리티 컨텍스트 principal에는 해당 엔티티를 구분할 수 있는 ID 정도의 문자열만 저장하자
- 따라서 @AuthenticationPrincipal에서 가져온 User를 조회할 때 연관 관계에 있는 엔티티가 지연 로딩으로 설정되어 있는 경우LazyInitializationException이 발생 !
- 해당 오류가 지난 TIL에서 정리한 내용이다.
프록시 객체와 entity equals
- 영속화 문제 외에도 필터로 받아온 user 엔티티와 게시글과 연관관계에 있는 user를 equals로 비교할 때 실제 값은 동일함에도 불구하고 왜 false가 반환되었는지 궁금해서 찾아보았다.
- Object의 equals 메소드: 주소값 비교
public boolean equals(Object obj) {
return (this == obj);
}
- 인텔리제이의 자동 생성 기능을 사용한 User에서 오버라이딩한 equals 메소드
- hibernate의 프록시 객체와 함께 사용되었을 때 문제 발생 !
- 프록시 객체 user에서 equals 호출 -> 실제 객체를 초기화(지연로딩)
- 실제 객체의 equals 호출 -> 실제 객체의 equals로 프록시 객체가 전달
- getClass() != o.getClass() 부분에서 실제 객체와 프록시 객체를 비교
- false 반환
- hibernate의 프록시 객체와 함께 사용되었을 때 문제 발생 !
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
User user = (User) o;
return Objects.equals(userId, user.userId) && Objects.equals(username,
user.username) && Objects.equals(password, user.password) && role == user.role;
}
- 해결 방법
- !(o instanceof User) 사용
- 실제 객체를 상속받은 프록시 객체가 들어와도 false를 반환하지 않음
- 하지만 프록시 객체 외에 User를 상속한 모든 타입에 대해 id가 같으면 true를 반환
- Hibernate.getClass(this) != Hibernate.getClass(o) 사용
- Hibernate.getClass: 프록시 타입이면 실제 객체의 클래스 타입을 반환
- !(o instanceof User) 사용
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || Hibernate.getClass(this) != Hibernate.getClass(o)) {
return false;
}
User user = (User) o;
return Objects.equals(userId, user.userId) && Objects.equals(username,
user.username) && Objects.equals(password, user.password) && role == user.role;
}
참고: https://ksh-dev.tistory.com/78
영속성 컨텍스트의 생존 범위와 트랜잭션의 범위가 같다
프록시 객체를 초기화하기 위해서는 영속성 컨텍스트가 필요하다고 알게 되었는데,
팀 과제를 수정하는 과정에서 프록시 객체를 초기화하기 위해 레포지토리에서 조회하여 객체를 반환받았다.
단순 조회할 때에도 영속성 컨텍스트가 유지될까? 라는 의문이 들었다.
- 스프링 컨테이너는 트랜잭션 범위의 영속성 컨텍스트 전략을 기본으로 사용
- 트랜잭션을 시작할 때 영속성 컨텍스트를 생성하고 트랜잭션이 끝날 때 영속성 컨텍스트를 종료한다.
- 트랜잭션 범위 밖의 영속성 컨텍스트는 보통 단순 조회성으로 사용하고, 지연로딩, 더티 체킹이 안된다.
- 프록시 객체를 레포지토리에서 조회함으로써 영속성 컨텍스트에서 초기화 가능하다.
'TIL' 카테고리의 다른 글
[231206] 프로그래머스 피로도 (Java) (0) | 2023.12.06 |
---|---|
[231204] 심화 주체 개인과제: 테스트 (0) | 2023.12.04 |
[231130] 팀과제 수정 (0) | 2023.11.30 |
[231129] 프록시와 영속성, 스프링 데이터 JPA (0) | 2023.11.29 |
[231128] Spring 숙련주차 팀과제, JPA 연관관계 (0) | 2023.11.28 |