Hibernate : session.get과 session.load의 차이점


88

API에서 프록시와 관련이 있음을 알 수 있습니다. 하지만 프록시에 대한 많은 정보를 찾을 수 없었고 호출 session.getsession.load. 누군가 나를 참조 페이지로 설명하거나 안내해 주시겠습니까?

감사합니다!!

답변:


117

로부터 최대 절전 모드 포럼 :

이것은 Hibernate in Action 책에서 발췌 한 것입니다. 잘 읽었어요 ..


식별자로 객체 검색 다음 Hibernate 코드 스 니펫은 데이터베이스에서 사용자 객체를 검색합니다.

User user = (User) session.get(User.class, userID);

get () 메서드는 식별자가 클래스의 단일 인스턴스를 고유하게 식별하기 때문에 특별합니다. 따라서 응용 프로그램에서 식별자를 영구 개체에 대한 편리한 핸들로 사용하는 것이 일반적입니다. 식별자 별 검색은 개체를 검색 할 때 캐시를 사용하여 개체가 이미 캐시 된 경우 데이터베이스 적중을 방지 할 수 있습니다. Hibernate는 또한 load () 메소드를 제공합니다 :

User user = (User) session.load(User.class, userID);

load () 메서드는 오래되었습니다. 사용자 요청으로 인해 Hibernate의 API에 get ()이 추가되었습니다. 차이점은 사소합니다.

load ()가 캐시 또는 데이터베이스에서 객체를 찾을 수 없으면 예외가 발생합니다. load () 메서드는 null을 반환하지 않습니다. get () 메서드는 객체를 찾을 수없는 경우 null을 반환합니다.

load () 메서드는 실제 영구 인스턴스 대신 프록시를 반환 할 수 있습니다. 프록시는 처음 액세스 할 때 실제 개체의로드를 트리거하는 자리 표시 자입니다. 반면에 get ()은 프록시를 반환하지 않습니다. get ()과 load () 중 하나를 선택하는 것은 쉽습니다. 영구 객체가 존재하고 존재하지 않는 것이 예외적 인 것으로 간주된다면 load ()가 좋은 옵션입니다. 주어진 식별자를 가진 영구 인스턴스가 있는지 확실하지 않은 경우 get ()을 사용하고 반환 값을 테스트하여 null인지 확인합니다. load ()를 사용하면 추가 의미가 있습니다. 애플리케이션은 영구 상태를 검색하기 위해 데이터베이스에 연결하지 않고도 영구 인스턴스에 대한 유효한 참조 (프록시)를 검색 할 수 있습니다. 따라서 load ()는 캐시 나 데이터베이스에서 영구 객체를 찾지 못하면 예외를 throw하지 않을 수 있습니다. 나중에 프록시에 액세스 할 때 예외가 발생합니다. 물론 식별자로 객체를 검색하는 것은 임의의 쿼리를 사용하는 것만 큼 유연하지 않습니다.


1
session.Get <T> ()가 프록시를 반환하는 문제를 지금 디버깅하고 있습니다!
Kent Boogaart

7
감사합니다! 저에게 돈 부분은 "load ()가 캐시 나 데이터베이스에서 객체를 찾을 수 없으면 예외가 발생합니다. 객체를 찾을 수 없으면 get () 메서드가 null을 반환합니다."
Chris

15
Session.get에 대한 JavaDoc은 다음과 같이 말합니다. 주어진 식별자를 사용하여 주어진 엔티티 클래스의 영구 인스턴스를 반환하거나 그러한 영구 인스턴스가 없으면 null을 반환합니다. (인스턴스 또는 인스턴스에 대한 프록시가 이미 세션과 연결되어있는 경우 해당 인스턴스 또는 프록시를 반환합니다.) 따라서 책의 섹션에서 "반면에 get ()은 프록시를 반환하지 않습니다." 정확하지 않습니다.
Vicky

daos와 함께 트랜잭션 관리 전략을 사용하는 경우 get ()을 선호 할 수 있습니다. 그렇지 않으면 load ()가 프록시를 반환하는 경우 호출자가 열린 최대 절전 모드 세션의 컨텍스트에서 실행해야합니다. 예를 들어 MVC를 수행하는 경우 컨트롤러는 dao.load ()를 실행 한 다음 유효한 세션이 없으면 나중에 프록시 개체에 액세스하려고 할 때 예외를 throw 할 수 있습니다. dao.get ()을 수행하면 세션에 관계없이 컨트롤러에 실제 객체가 반환됩니다 (존재한다고 가정)
dev

@Vicky가 설명한 문제는 두통을 유발할 수 있으며 이점이 없다고 생각합니다. 어떤 경우에는 추가 매개 변수화 된 쿼리에 대한 식별자가 추가로 필요합니다. 그러나 객체의 프록시가 이미 세션에 있으므로 식별자의 getter는 null을 반환합니다. 프록시가 세션에있는 경우 실제 인스턴스 대신 프록시를 검색하는 이유는 무엇입니까?
djmj

15

음, 적어도 nhibernate에서 session.Get (id)는 데이터베이스에서 객체를로드하는 반면 session.Load (id)는 서버를 떠나지 않고 프록시 객체 만 생성합니다. POCO (또는 POJO :)의 다른 모든 지연로드 된 속성처럼 작동합니다. 그런 다음이 프록시를 개체 자체에 대한 참조로 사용하여 관계 등을 만들 수 있습니다.

Id 만 유지하고 필요한 경우 나머지를로드하는 개체가있는 것처럼 생각하십시오. 관계 (예 : FK)를 생성하기 위해 전달하는 경우 ID 만 있으면됩니다.


그래서 당신은 load (id)가 유효한 id인지 아닌지를 확인하기 위해 먼저 데이터베이스를 치고 프록시 객체를 반환 하고이 객체의 속성에 액세스하면 데이터베이스에 다시 도달한다고 말하고 싶습니까? 가능성이없는 시나리오 아닌가요? 단일 개체를로드하는 두 개의 쿼리?
faisalbhagat 14:44에

아니요, load (id)는 ID를 전혀 확인하지 않으므로 DB 로의 왕복이 없습니다. 유효하다고 확신 할 때만 사용하십시오.
Jorge Alves

9

session.load ()는 데이터베이스에 접속하지 않고 항상 "proxy"(Hibernate 용어)를 반환합니다. Hibernate에서 proxy는 주어진 식별자 값을 가진 객체이고, 그것의 속성은 아직 초기화되지 않았으며, 단지 임시 가짜 객체처럼 보입니다. 행이 없으면 ObjectNotFoundException이 발생합니다.

session.get ()은 항상 데이터베이스를 검색하고 프록시가 아닌 데이터베이스 행을 나타내는 개체 인 실제 개체를 반환합니다. 행이 없으면 null을 반환합니다.

이러한 방법을 사용한 성능도 diff를 만듭니다. 둘 사이 ...


3

추가 포인트 ::

Hibernate Session 클래스의 get 메소드는 객체가 데이터베이스뿐만 아니라 캐시에서도 발견되지 않으면 null을 반환합니다. load () 메서드는 객체가 데이터베이스뿐만 아니라 캐시에서도 발견되지 않고 null을 반환하지 않는 경우 ObjectNotFoundException을 throw합니다.


2

"get"대신 "load"를 사용하는 간접적 인 결과는 버전 속성을 사용하는 낙관적 잠금이 예상대로 작동하지 않을 수 있다는 것입니다. 로드가 단순히 프록시를 만들고 데이터베이스에서 읽지 않으면 version 속성이로드되지 않습니다. 버전은 나중에 객체의 속성을 참조하여 선택을 트리거하는 경우에만로드됩니다. 그 동안 다른 세션에서 객체를 업데이트 할 수 있으며 세션에 낙관적 잠금 검사를 수행하는 데 필요한 원래 버전이 없으므로 세션의 업데이트가 경고없이 다른 세션의 업데이트를 덮어 씁니다.

다음은 동일한 식별자를 가진 개체로 작업하는 두 세션으로이 시나리오를 스케치하려는 시도입니다. DB에있는 객체의 초기 버전은 10입니다.

Session 1                  Session 2
---------                  ---------
Load object
Wait a while..   
                           Load object
                           Modify object property
                           [triggers db 'select' -
                            version read as 10]
                           Commit
                           [triggers db update,
                            version modified to 11]
Modify object property
  [triggers db 'select' -
  version read as 11]
Commit
  [triggers db update,
  version modified to 12]

우리는 실제로 낙관적 잠금 예외와 함께 세션 1의 커밋이 실패하기를 원하지만 여기서 성공할 것입니다.

"load"대신 "get"을 사용하면 get이 즉시 선택을 실행하고 낙관적 잠금 검사를 위해 올바른 시간에 버전 번호가로드되기 때문에 문제를 해결할 수 있습니다.


0

또한 객체가 없으면 예외가 발생하므로 load를 사용하는 동안주의해야합니다. 우리는 객체가 존재한다고 확신 할 때만 사용해야합니다.


0

훌륭한 설명은에서 찾을 수 http://www.mkyong.com/hibernate/different-between-session-get-and-session-load
만일 Session.load () :
그것은 항상 "프록시"(최대 절전 용어를) 반환하지 않고 데이터베이스를 치는 것.
Hibernate에서 proxy는 주어진 식별자 값을 가진 객체이고, 그것의 속성은 아직 초기화되지 않았으며, 단지 임시 가짜 객체처럼 보입니다.
ID 값이 데이터베이스에 존재하지 않더라도 항상 주어진 ID 값을 가진 프록시 객체를 반환합니다. 그러나 데이터베이스에서 속성을 검색하여 프록시를 초기화하려고하면 select 문을 사용하여 데이터베이스에 충돌합니다. 행이 없으면 ObjectNotFoundException이 발생합니다.
session.get () :
항상 데이터베이스 (캐시에서 찾을 수없는 경우)를 검색하고 프록시가 아닌 데이터베이스 행을 나타내는 개체 인 실제 개체를 반환합니다.
행이 없으면 null을 반환합니다.


0

load ()가 캐시 또는 데이터베이스에서 객체를 찾을 수 없으며 예외가 발생하고 load () 메서드가 null을 반환하지 않습니다.

get () 메서드는 객체를 찾을 수없는 경우 null을 반환합니다. load () 메서드는 실제 영구 인스턴스 대신 프록시를 반환 할 수 있습니다. get ()은 프록시를 반환하지 않습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.