2017-01-18 1 views
0

Hibernate는 트랜잭션 메소드에서 수정 된 엔티티를 유지하므로 세션 # evict (엔티티)를 사용하여 피할 수있다.Hibernate에서 영속 컨텍스트로부터 엔티티 내의 엔티티를 분리

퍼시스턴스 컨텍스트에서 분리하면 해당 컨텍스트도 분리됩니다. 주소가 트랜잭션의 끝에서 지속 될 것입니다, 나는 사용자 개체를 분리하는 경우

@Entity 
public class User extends BaseEntity{ 
     @Column(name = "email") 
     private String email; 

     @OneToMany(fetch = FetchType.LAZY, mappedBy = "user") 
     private List<Address> addresses; 

     // getters and setters 
} 

@Entity 
public class Address extends BaseEntity{ 
     @Column(name = "email") 
     private String email; 

     @ManyToOne(fetch = FetchType.LAZY) 
     @JoinColumn(name = "USER_ID") 
     private User user;  

     // getters and setters 
} 

만에 주소 객체를 변경 : 예를 들어

, 나는이 수업을? 이처럼 :

User user = userDAO.getById(id); 
session.evict(user); 
Address address = user.getAddresses().get(0); 
address.setNumber(number); 
addressDAO.saveOrUpdate(address); //will this work? 
+0

왜 사용자를 (명시 적으로) 분리하겠습니까? JPA는로드 된 모든 엔티티의 복사본을 메모리에 보관합니다. 트랜잭션이 커밋되면 Persistence Context를 통해 실행되고 수정 된 엔티티를 찾습니다. 이렇게하면 사용자를 수정하지 않으면 사용자에게 아무런 변화가 없습니다. –

+0

사용자를 변경하는 줄을 생략했습니다. 예제에 추가해야 할 수도 있습니다. 하지만 일괄 업데이트를하고 있기 때문에 분리하고 있으므로 각 엔티티를 개별적으로 저장하지 않아도됩니다. –

+0

당신이''CascadeType.DETACH/ALL''을 전파시키지 않는 한 각각의 엔티티에 대해 분리가 이루어집니다. saveOrUpdate()는 주소 변경 사항이 데이터베이스에 도달 할 수 있도록 충분해야합니다 (단, JPA와 마찬가지로 작동하는 경우 관리 엔티티의 변경 사항이 트랙이므로 필요하지 않음). 그러나 CascadeType.UPDATE가있는 엔티티를 업데이트하는 경우 분리 된 엔티티로 전달되는 문제가 발생할 수 있다고 생각합니다. * 대량 업데이트 * 란 무엇입니까? 나는 500MB 크기의 거래를 해왔고 결코 분리 할 필요가 없었다. –

답변

1

엔티티이 만 선택 쿼리 발생, 영속 컨텍스트에로드되지 않습니다 당신이 find() 또는 merge()를 사용하는 경우.

업데이트 또는 삭제 쿼리를 수행 한 후에는 영속 컨텍스트에 이미로드 된 엔터티를 쿼리가 업데이트하지 않기 때문에 지속성 컨텍스트가 데이터베이스와 실제로 동기화되지 않을 수 있습니다 (호출해야 함 변경 사항을 보려면 refresh()).

사용자를 지속성 컨텍스트에로드하고 나중에 Update User set status='active' where id IN (:ids)을로드 한 다음 지속성 컨텍스트에서 사용자를 수정하지 않은 경우 데이터베이스 만 수정했습니다. 사용자를 수정하려면,`aUser.setStatus ('active')를 호출하여 실제로 관리되는 Entity를 수정해야하며, 트랜잭션이 커밋 될 때 JPA는 모든 관리 엔티티가로드 될 때 생성 된 복사본에 대해 검사 할 것이고, 업데이트를 할 것입니다.

지속성에 5000 개의 객체를로드하는 경우 JPA가 엔티티 그래프를 통해 실행될 때까지 약간의 시간이 소요될 수 있으며 트랜잭션이 커밋 될 때 변경 사항을 감지 할 수 있습니다. 아무 것도 수정하지 않고 변경 감지 속도를 높이려면 두 가지 방법이 있습니다. 읽기 전용 쿼리를 사용하여 엔티티를로드하면 JPA에로드 된 엔티티의 사본을 보관할 필요가 없음을 알립니다. 다른 옵션은 EntityManager.clear()으로 전화하여 모든 관리 엔티티를 버리는 것입니다. 그러나 성능에 관심이 있다면 가장 좋은 해결책은 엔티티를 지속성 컨텍스트에로드하지 않는 것입니다. 문제를 이해 했으므로 Update User set ... where id IN (:ids)을 수행해야하며 사용자 ID 만 필요하므로 사용자를로드 할 필요가 없으므로 ID가 필요하므로 수행 할 수 있습니다. List<Long> ids = em.createQuery("select u.id from User u where ...", Long.class).getResultList();

희망 당신을 위해 일을 명확히 :

편집 :이는 JPA의 관점에서 작성하지만, 행동이 정확히 같은 find()를 제외하고, 설명, 그래서 그냥 앞으로 직접 SessionImpl에 최대 절전 모드 EntityManager, 네이티브 Hibernate에서 get()을 호출되고.

+0

으로 지정하십시오. 읽기 전용 쿼리를 말할 때 주석이 @Transactional (readOnly = true)입니까? 그런 다음 "select id"쿼리를 사용하여 readOnly가 아닌 매개 변수로 전달하면 충분합니다. –

+0

전체 트랜잭션이 읽기 전용 인 경우 대량 업데이트가 작동하지 않습니다. 단일 쿼리를 읽기 전용으로 사용하려면'@QueryHint()'를 사용해야 할 것이지만 쿼리 힌트는 벤더에 따라 다르다. 'User.id' 만 선택하면 EntityManager에 아무것도로드되지 않으므로 읽기 전용 쿼리가 필요 없습니다 (id 필드는 엔터티가 아닙니다). Hibernate를 사용한다면 항상 중단 점을 설정하고'Session.persistenceContext.entitiesByKey' 필드를 체크 할 수 있습니다. 이것은 현재 Persistence Context에로드되어있는 것을 보여줍니다. –

0

는 JPA 2.0

때문에 매개 변수로 분리 될하는 EntityManager의 원하는 엔티티와 분리 호출 할 수 있습니다 주어진다면 here

void detach(Object entity) 

더 당신은 필요한 엔티티를 분리하고자하는 서비스에 EntityManger를 삽입 할 수 있습니다. 업데이트 또는 EntityManager.createQuery()을 사용하여 삭제합니다

+0

유감스럽게도 EntityManager를 사용하지 않지만 최대 절전 모드에서 sessionFactory를 –

관련 문제