본문 바로가기

TIL

[TIL 2022-02-22] JPA 프록시에 대해서, Set의 equals

JPA 프록시(Hibernate에서)

하이버네이트는 EntityManger의 getReference() 메소드 호출시, 조회하고자 하는 객체를 상속받는 프록시 객체를 만들어 반환한다. 프록시 객체는 메소드 호출 즉시 데이터베이스에 select를 호출하는 것이 아니라, 개발자가 실제 매핑된 데이터를 조회하고자 할 때 데이터베이스에서 데이터를 가져온다. 

 

아래 코드와 실행 결과를 보면 getRefernce() 호출이 아닌 getName() 메소드 호출 시점에 데이터베이스에 select 쿼리를 날리고 데이터를 가져오는 것을 알 수 있다.

Member 객체를 데이터베이스에 저장하고 getRefernce 메소드를 통해 조회
코드 실행 결과

위의 결과처럼 getName()메소드 호출 시 Member 객체와 매핑되어있는 테이블에서 데이터를 조회한다. 프록시 객체는 실제 엔티티 객체를 참조하는 target을 보관한다.(필드를 갖는다는 것 같은데 아직 잘 모르겠다) 앞의 과정에서 조회된 데이터는 매핑된 Member 객체를 생성하고 target 은 이를 참조한다. 때문에 getName() 메소드를 호출하면 프록시 객체의 target을 통해 getName() 메소드가 호출되고 "unannn" 이 찍히게 된 것이다.

 

 

또 프록시 객체는 아래와 같은 특성을 가진다.

 

- 프록시 객체는 원본 엔티티를 상속받기 때문에 타입 체크시 == 이 아닌 instance of 를 사용해야한다.

 

- 영속성 컨텍스트에 엔티티가 존재하면 getReference() 메소드를 사용해도 프록시가 아닌 실제 객체를 조회함

이미 영속성 컨텍스트에 실제 엔티티가 존재하면 프록시를 만들 이유가 없다. JPA의 프록시 객체는 한번에 모든 데이터를 데이터베이스에서 가져오는게 아니라 필요할 때 마다 가져올 수 있도록 하는 것인데 이미 영속화 되어있다는 것은 이미 조회를 했다는 것을 뜻한다.

 

- 영속성 컨텍스트의 도움을 받을 수 없는 준영속 상태일 때, 프록시를 초기화 하면 문제 발생 

 

프로그래머스 level2 - 방문 길이

https://programmers.co.kr/learn/courses/30/lessons/49994

 

코딩테스트 연습 - 방문 길이

 

programmers.co.kr

좌표 병면에서 명령어에 따라 경로를 이동하면서 중복되지 않는 이동경로의 개수를 찾는 문제였다. 처음에는 좌표 (1, 2) 에서 (1, 3) 로 이동 했다고 치면 경로 문자열 "1213"을 리스트에 저장하고, 이미 리스트에 존재할 경우 저장하지 않는 방식으로 코드를 짰었다. 그런데 생각해보니까 (1, 3) 에서 (1, 2) 로 이동할 경우 경로 문자열이 "1312" 가 되기 때문에 새로운 경로로 처리되어 카운트되는 문제가 생겼다. 이를 해결하기 위해 Set 자료형을 활용했다.

 

Set의 특성 때문에 아주쉽게 해결할 수 있었는데 첫번째는 Set 의 equals() 메소드는 집합의 크기가 동일하고 둘다 같은 요소를 포함하는 경우 true를 반환한다. 이는 부모 클래스인 AbstractSet 에 정의 되어있다.

AbstractSet에서 오버라이드된 equals() 메소드

두개의 다른 Set 객체를 비교할 때, 두 Set의 크기가 같으면 AbstractSet의 부모 클래스인 AbstractCollection 클래스의 containAll() 메소드가 호출된다.

AbstractCollection의 containsAll()메소드

이 메소드에서 루프를 통해 Set 안에 요소들을 하나씩 비교해 모두 같으면 true를 반환하는 것이다. 때문에 Set 의 equals 메소드는 두 Set 객체가 같은 요소들을 포함하고 있는지를 비교하고, ArrayList의 contains 메소드 또한 equals 메소드를 통해 리스트 내에 객체가 존재하는지 비교하기 때문에 기존의 문자열을 비교하는 방식에서 큰 변경없이 코드를 수정할 수 있었다. 코드는 아래와 같다.

 

https://github.com/unannn/CodingTestPractice/blob/main/programmers/level2/%EB%B0%A9%EB%AC%B8%20%EA%B8%B8%EC%9D%B4.java

 

GitHub - unannn/CodingTestPractice: 코딩테스트 연습 문제 풀이 Repo 입니다.

코딩테스트 연습 문제 풀이 Repo 입니다. Contribute to unannn/CodingTestPractice development by creating an account on GitHub.

github.com