programing

최대 절전 모드에서 분리된 객체를 다시 연결하는 적절한 방법은 무엇인가?

prostudy 2022. 5. 17. 21:55
반응형

최대 절전 모드에서 분리된 객체를 다시 연결하는 적절한 방법은 무엇인가?

동일한 ID MAY의 물체가 세션에 이미 존재하기 때문에 오류가 발생할 수 있지만, 분리된 물체를 최대 절전 모드에 다시 연결해야 하는 상황이 있다.

지금 당장은 두 가지 중 하나를 할 수 있다.

  1. getHibernateTemplate().update( obj )크다면 만약 이미 개체는 겨울잠을 자다 세션에 존재하지 않는 이 일한다.이는 최대 절전 모드 세션에 개체가 아직 존재하지 않는 경우에만 작동한다.예외는 추후에 그것을 필요로 하는 주어진 식별자와 이미 개체는 이번 임시 국회에서 존재한다는 내용을 명시한 throw 됩니다.나중에 필요할 때 세션에 지정된 식별자를 가진 객체가 이미 존재한다는 예외가 발생함

  2. getHibernateTemplate().merge( obj )만일 개체를 피한 세션에 존재하는 이 일한다.이는 최대 절전 모드 세션에 개체가 존재하는 경우에만 작동한다.때 제가 나는 이것을 이용하여는 세션에서 후에 개체가 필요해 예외가 throw 됩니다.나중에 개체를 세션에 사용해야 할 경우 예외가 발생함

이 두 가지 시나리오를 고려할 때 어떻게 세션을 객체에 일반적으로 연결할 수 있는가?이 문제 해결책의 흐름을 조절하기 위해 예외를 사용하고 싶지는 않다, 보다 우아한 해결책이 있어야 하기 때문이다...

그래서 JPA에 케케묵은 분리조직을 다시 붙일 방법이 없어 보인다.

merge()는 DB에 명령하고, 어떤intervening 업데이트를 덮어쓴 상태 추진할 것이다.오래된 상태를 DB로 밀어넣고, 업데이트에 방해가 되는 모든 업데이트를 덮어쓸 것이다.

refresh()공정한 기관이라고 불릴 수 없습니다.독립된 기관에 요청할수 없다.

lock()공정한 단체에 하더라도, 수 있고, 이것은 '주장 'LockMode과 'lock에 전화하는 실체 다시 부착해야 할 수 없습니다.독립된기업에는호출할 수 없으며,그럴수 있다고 하더라도, 그것은 '락모드'라는 주장으로 '락모드'를 부르면서 다시 연결시켰다.API디자인의 내가 seen."요 NONE'은, 하지만 잠그지 않고 있는 것을 암시하고, 가장 직관적 작품이다.NONE"은 잠가보지만 잠가보지는 않는다는 의미로 내가 본 API디자인 중가장직관에 반하는 부분이다.

그러니까 넌 딱 붙어 있습니다.그래서 넌 꼼짝도 못하고 있는 거야.한라는 것이 있다 있다.detach()법이 없는 방법,그러나 아니다attach()또는 또는reattach(). 개체를 라이프 사이클에 대한 분명한 조치이여서 이용할 수 없다객체 라이프사이클의 분명한 단계는 사용할 수 없다.

JPA에 관한 유사한 질문의 수로 미루어 볼 때, JPA가 일관성 있는 모델을 가지고 있다고 주장하더라도, JPA가 가장 간단한 일을 하게 하는 방법을 이해하느라 많은 시간을 허비하고 그들의 어플리케이션 전체에 캐시 관리 코드를 가지고 있다는 저주를 받은 대부분의 프로그래머들의 정신적 모델과는 확실히 일치하지 않는 것 같다.이온

그렇게 하는 유일한 방법은 당신의 오래된 분리된 실체를 버리고 L2나 DB를 칠 동일한 아이디로 조회하는 것이다.

미크

이 모든 해답은 중요한 차이를 놓친다.update()는 객체 그래프를 세션에 첨부하는 데 사용된다.당신이 통과시킨 물체는 관리하게 되는 물체들이다.

merge()는 실제로 (재)첨부 API가 아니다.공지사항 병합()에 반환 값이 있는가?관리 그래프를 반환하기 때문인데, 이 그래프는 사용자가 통과한 그래프가 아닐 수 있다. merge()는 JPA API이며 그 동작은 JPA 규격에 의해 제어된다.병합()에 전달하는 개체가 이미 관리되어 있는 경우(세션과 이미 연관되어 있음) 최대 절전 모드 그래프와 함께 작동하며, 전달된 개체는 병합()에서 반환된 개체와 동일하다.그러나 병합()에 통과하는 객체가 분리된 경우, 최대 절전 모드에서는 관리되는 새 객체 그래프를 생성하고 분리된 그래프에서 새 관리되는 그래프로 상태를 복사한다.다시 말하지만, 이것은 모두 JPA 규격에 의해 지시되고 관리된다.

"이 실체가 관리되고 있는지 또는 관리되고 있는지"에 대한 일반적인 전략의 측면에서도, 삽입되지 않은 데이터도 회계처리할 것인지에 따라 달라진다.그렇다고 가정할 때 이런 걸 쓰세요.

if ( session.contains( myEntity ) ) {
    // nothing to do... myEntity is already associated with the session
}
else {
    session.saveOrUpdate( myEntity );
}

업데이트() 대신 saveOrUpdate()를 사용했다는 점에 유의하십시오.여기에 삽입되지 않은 데이터를 처리하지 않으려면 대신 업데이트()를 사용하십시오.

엔티티 상태

JPA는 다음과 같은 실체 상태를 정의한다.

신규(투명)

그것은 최대 절전 모드 최대 절전 모드와 연결되지 않은 새로 생성된 개체와 관련된 오지 않고 있어 새로 만든 개체다.Session((실내 실내)Persistence Context탭을 클릭하고 원하는 데이터베이스 테이블 열로 매핑 되지 않는다는 점은 새로운(과도)주에 있는데.)으로 간주된다.및 어떤 데이터베이스 테이블 행에도 매핑되지 않으며 새(투명)상태로 간주된다.

지속되는이 되기 위해서 우리들 중 명시적으로버텨내려면 우리는걸어야 한다 전화를 명시적으로이라고 할 필요가 있다.EntityManager#persist법 또는서 지속성 메커니즘의 사용하여라.전이 지속성 메커니즘의 방법 또는 사용.

영구(관리됨)

영구 엔터티가 데이터베이스 테이블 행과 연결되었으며 현재 실행 중인 지속성 컨텍스트에 의해 관리되고 있는 경우.그러한 기업에 대한 변경사항은 (세션 플러시 시간 동안) 탐지되어 데이터베이스로 전파될 것이다.

최대 절전 모드로, 우리는 더 이상INSERT/UPDATE/DELETE 진술 처형시켜최대 절전 모드에서는 INSERT/UPDATE/DELETE 문을 더 이상 실행할 필요가 없다.최대 절전 모드에서는 트랜잭션 쓰기-백그라운드 작업 방식을 사용하며 현재 상황에서 가장 마지막 책임 순간에 변경 사항이 동기화됨Session플러시 타임

분리됨

현재 실행 중인 지속성 컨텍스트가 닫히면 이전에 관리하던 모든 엔티티가 분리된다.연속적인 변경은 더 이상 추적되지 않을 것이며 자동 데이터베이스 동기화는 일어나지 않을 것이다.

엔티티 상태 변환

당신은 실체 상태 다양한 메서드를에서 정의된를 사용하여 변경할 수 있습니다.EntityManager인터페이스입니다.

더 일본 조달청 기관 상태 변환을 이해하려면 다음 다음 다이어그램과 같이 고려해 보세요.

일본 조달청 기관 상태 변환

언제, 적극적으로 공정한 실체 재연합하다에 일본 조달청을 이용해EntityManager, 당신은 합병 작업을 사용할 수 있다.

언제가 최대 절전 모드 API, 떨어져에게.merge다음 도표에 의해 증명되었는데 여러분은 활동적인 최대 절전 모드 Sessionusing 업데이트 방법:단독 실체 다시 부착할 수 있다.

실체 상태 변환Hibernate

공정한 실체 Merging

그 합병은 분리된 실체 상태를 관리되는 엔티티 인스턴스(목적지)에(소스)을 복사할 것이다.

우리는 다음이 계속되는가를 생각해 보자.Book엔티티는 이제 실체와 분리되지 않습니다.EntityManager그것은 실체 닫혔다 지속되기:사용되었다.

Book _book = doInJPA(entityManager -> {
    Book book = new Book()
    .setIsbn("978-9730228236")
    .setTitle("High-Performance Java Persistence")
    .setAuthor("Vlad Mihalcea");
 
    entityManager.persist(book);
 
    return book;
});

반면 기관은 분리된 상태이다 다음과 같이 우리가:를 수식한다.

_book.setTitle(
    "High-Performance Java Persistence, 2nd edition"
);

그래서 우리는 전화할 수 있어 이제, 우리는 데이터베이스에 대한 변경이 전파되도록 하고 싶다.merge메서드

doInJPA(entityManager -> {
    Book book = entityManager.merge(_book);
 
    LOGGER.info("Merging the Book entity");
 
    assertFalse(book == _book);
});

그리고 최대 절전 모드는 다음 SQL문을 실행하기 위하여:계속 있다.

SELECT
    b.id,
    b.author AS author2_0_,
    b.isbn AS isbn3_0_,
    b.title AS title4_0_
FROM
    book b
WHERE
    b.id = 1
 
-- Merging the Book entity
 
UPDATE
    book
SET
    author = 'Vlad Mihalcea',
    isbn = '978-9730228236',
    title = 'High-Performance Java Persistence, 2nd edition'
WHERE
    id = 1

만약 합병하는 현재에 없습니다.EntityManager, 신선한 실체 사진 데이터베이스에서 페치 될 것이다.

옛날에 관리되는 주체는, 일본 조달청 현재 관리되는 환자가 그 끈기 있어야=컨텍스트 동안에 분리된 실체의 상태 따라 한다.flush만약 더러운 검사 메커니즘은 관리되는 실체 변한 것을 알게 된 업데이트 생성된다.

그래설 때 쓴다merge, 분리된 개체 인스턴스가 합병 작업 후에도 초연하게 유지하기 위해 계속될 것이다.

공정한 실체 Reattaching

최대 절전 모드, 아니지만 일본 조달청을 통해 재부 착시를 지원합니다.update방법.

A최대 절전 모드Session단지 주어진 데이터베이스 열에 대해서 하나의 독립체 개체를 사귈 수 있다.때문에 끈기 있어야=-메모리 내 캐시(첫번째 수준 캐시)로(실체) 주어진 키(엔티티 유형 및 데이터베이스 식별자)과 관련된은 단지 하나의 값을 행동하기 때문이다.

없을 때만 다른 JVM개체( 같은 데이터베이스 행과 일치하는)이미 현재 최대 절전 모드와 연관이 있는 기관 이상 재부착될 수 있다.Session.

우리는이 계속되는가를 고려하다.Book엔티티고 우리가 그것이 수정했다.Book엔티티는 분리된 상태에 있었다.

Book _book = doInJPA(entityManager -> {
    Book book = new Book()
    .setIsbn("978-9730228236")
    .setTitle("High-Performance Java Persistence")
    .setAuthor("Vlad Mihalcea");
 
    entityManager.persist(book);
 
    return book;
});
      
_book.setTitle(
    "High-Performance Java Persistence, 2nd edition"
);

우리는 다음과 같이 분리된 실체를 다시 부착할 수 있다.

doInJPA(entityManager -> {
    Session session = entityManager.unwrap(Session.class);
 
    session.update(_book);
 
    LOGGER.info("Updating the Book entity");
});

그리고 최대 절전 모드에서는 다음과 같은 SQL 문이 실행된다.

-- Updating the Book entity
 
UPDATE
    book
SET
    author = 'Vlad Mihalcea',
    isbn = '978-9730228236',
    title = 'High-Performance Java Persistence, 2nd edition'
WHERE
    id = 1

update방법은 당신이 해야 한다unwrapEntityManager겨울잠을 자다Session.

와는 달리merge제공된 분리된 엔터티는 현재 지속성 컨텍스트와 재조정되며, 엔터티가 수정되었는지 여부에 관계없이 플러시 중에 업데이트 일정이 잡힌다.

이 지만하 기 를 하면 @SelectBeforeUpdate더티 체크 메커니즘에 의해 사용되는 로드된 상태를 가져온 SELECT 문을 트리거하는 최대 절전 모드 주석.

@Entity(name = "Book")
@Table(name = "book")
@SelectBeforeUpdate
public class Book {
 
    //Code omitted for brevity
}

Non UniqueObjectException 주의

에 발생할 수 있는 한 가지 문제update지속성 컨텍스트에 다음 예시와 동일한 ID와 유형의 엔티티 참조가 이미 포함되어 있는 경우:

Book _book = doInJPA(entityManager -> {
    Book book = new Book()
    .setIsbn("978-9730228236")
    .setTitle("High-Performance Java Persistence")
    .setAuthor("Vlad Mihalcea");
 
    Session session = entityManager.unwrap(Session.class);
    session.saveOrUpdate(book);
 
    return book;
});
 
_book.setTitle(
    "High-Performance Java Persistence, 2nd edition"
);
 
try {
    doInJPA(entityManager -> {
        Book book = entityManager.find(
            Book.class,
            _book.getId()
        );
 
        Session session = entityManager.unwrap(Session.class);
        session.saveOrUpdate(_book);
    });
} catch (NonUniqueObjectException e) {
    LOGGER.error(
        "The Persistence Context cannot hold " +
        "two representations of the same entity",
        e
    );
}

이제 위의 테스트 케이스를 실행할 때, 최대 절전 모드에서는NonUniqueObjectException두 번째가 되기 때문에EntityManager이미 a를 포함하고 있다.Book 당사가 이전하는 것과 동일한 식별자를 가진 도면요소update그리고 지속성 컨텍스트는 동일한 엔터티의 두 가지 표현을 포함할 수 없다.

org.hibernate.NonUniqueObjectException:
    A different object with the same identifier value was already associated with the session : [com.vladmihalcea.book.hpjp.hibernate.pc.Book#1]
    at org.hibernate.engine.internal.StatefulPersistenceContext.checkUniqueness(StatefulPersistenceContext.java:651)
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.performUpdate(DefaultSaveOrUpdateEventListener.java:284)
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.entityIsDetached(DefaultSaveOrUpdateEventListener.java:227)
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:92)
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:73)
    at org.hibernate.internal.SessionImpl.fireSaveOrUpdate(SessionImpl.java:682)
    at org.hibernate.internal.SessionImpl.saveOrUpdate(SessionImpl.java:674)

결론

merge낙천적인 잠금을 사용하는 경우 업데이트 손실을 방지할 수 있는 방법이 선호된다.

update에 의해 생성되는 추가 선택 문을 방지할 수 있으므로 배치 업데이트에 적합하다.merge따라서 배치 업데이트 실행 시간 단축.

비외교적 답변:당신은 아마도 확장된 지속성의 맥락을 찾고 있을 것이다.이게프레임워크의 주요 이유 중 하나야특히 봄에 동면기를 사용하기 위해 애쓰고 있다면, 이 심의 문서를 확인하십시오.

외교적 답변:이것은 최대 절전 모드 문서에 설명되어 있다.자세한 설명이 필요한 경우, "분리된 개체로 작업"이라고 하는 최대 절전 모드를 사용한 Java Persistence의 섹션 9.3.2를 살펴보십시오.겨울잠이 있는 CRUD 이상의 일을 하고 있다면 이 책을 권하고 싶다.

엔티티가 수정되지 않았음이 확실하다면(또는 수정 내용이 손실될 것이라는 데 동의하는 경우), 잠금 장치를 사용하여 세션에 다시 첨부할 수 있다.

session.lock(entity, LockMode.NONE);

아무것도 잠그지 않지만, 세션 캐시에서 엔티티를 가져오거나 DB에서 읽어 올 것이다.

그것은 매우 게으른 것을 막는 것이 유용하다.InitException 때"오래 된"(그 HttpSession 예를 들어에서)단체의 관계를 지휘하고 있다.당신은 먼저 실체"re-attach".

get를 사용하는 것 또한,)상속이 매핑 된(이미getId에 예외를 throw 합니다()을 제외하고 일할 수도 있다.

entity = session.get(entity.getClass(), entity.getId());

는 자바닥을 .org.hibernate.Session다음과 같은을 찾으셨다.

일시적인 인스턴스 영구를 호출하여 만들어질 수 있습니다.save()persist()또는saveOrUpdate(). 지속적인 인스턴스 과도를 호출하여 만들어질 수 있습니다.delete(). 모든 인스턴스 a에서 반환get()또는load()법 매우 집요하다.군 사례 집요한를 호출하여 만들어질 수 있습니다.update()saveOrUpdate()lock()또는replicate(). 과도 현상 또는 인스턴스의 주들 또한 지속적인 새로운 지속적인 인스턴스를 호출하여 만들어질 수 있습니다.merge().

따라서update()saveOrUpdate()lock()replicate()그리고.merge()그 후보 선택이다.

update()만약 동일한 식별자가 끈질긴 인스턴스가:예외를 throw 할 것이다.

saveOrUpdate():그것은 받아들거나 갱신을 구하

lock()되지 않음:사용되지 않습니다

replicate():, 현재의 식별자 값 다시 지정된 분리 인스턴스의 상태 Persist.

merge():동일한 식별자가 영구 개체를 반환합니다.지정된 인스턴스를 세션에 연관되게 되지 않는다.

이런 이유로,lock()직렬과 하나 또는 더 많은 여성들이 선택할 수 있는 기능 요건을 기준으로 해서는 안 됩니다.

I did it that way in C# with NHibernate, but it should work the same way in Java:

public virtual void Attach()
{
    if (!HibernateSessionManager.Instance.GetSession().Contains(this))
    {
        ISession session = HibernateSessionManager.Instance.GetSession();
        using (ITransaction t = session.BeginTransaction())
        {
            session.Lock(this, NHibernate.LockMode.None);
            t.Commit();
        }
    }
}

왜냐하면항상 잘못된 제1Lock모든개체에 소환됐다 포함합니다.문제는 NHibernate 데이터베이스 아이디와 형식으로 개체를 비교한다.문제는 NHibernate형식으로 개체를 비교한다 아이디와 데이터베이스.포함합니다는 포함합니다를 사용하를 사용한다equals법, 덮어씌울 수도 있지 않는 참조로 비교한다.법, 덮어씌울 수도 있지 않는 참조로 비교한다.그 저것을 가지고로equals방법 그것은 어떤 예외 없이: 일한다.방법 그것은 어떤예외 없이:일한다.

public override bool Equals(object obj)
{
    if (this == obj) { 
        return true;
    } 
    if (GetType() != obj.GetType()) {
        return false;
    }
    if (Id != ((BaseObject)obj).Id)
    {
        return false;
    }
    return true;
}

Session.contains(Object obj)확인합니다 참조 및 그리고 그건 이미에 첨부된 같은 열의를 나타내는 다른 인스턴스를 감지하지 못할 것이다.확인합니다 참조 및 그리고 그건 이미에 첨부된 같은 열의를 나타내는 다른 인스턴스를 감지하지 못할 것이다.

식별자 속성에 Entities을 위한 내 일반적인 해결책이다.

public static void update(final Session session, final Object entity)
{
    // if the given instance is in session, nothing to do
    if (session.contains(entity))
        return;

    // check if there is already a different attached instance representing the same row
    final ClassMetadata classMetadata = session.getSessionFactory().getClassMetadata(entity.getClass());
    final Serializable identifier = classMetadata.getIdentifier(entity, (SessionImplementor) session);

    final Object sessionEntity = session.load(entity.getClass(), identifier);
    // override changes, last call to update wins
    if (sessionEntity != null)
        session.evict(sessionEntity);
    session.update(entity);
}

이것은 하나의 거의 없는 면이다.내가 좋아하는 Net EntityFramework는 변경된 엔티티와 그 속성에 관한 서로 다른 첨부 옵션이다.

세션에 이미 연결되어 있을 수 있는 다른 개체를 설명하는 지속성 저장소에서 개체를 "새로 고치는" 방법을 생각해 냈다.

public void refreshDetached(T entity, Long id)
{
    // Check for any OTHER instances already attached to the session since
    // refresh will not work if there are any.
    T attached = (T) session.load(getPersistentClass(), id);
    if (attached != entity)
    {
        session.evict(attached);
        session.lock(entity, LockMode.NONE);
    }
    session.refresh(entity);
}

미안해요,(아직?)답글을 없을 것 같습니다.

3.5.0-Final 최대 절전 모드 사용

그 반면에는 반면에Session#lock법 이 사용되지 않는 javadoc 사용을 시사한다.Session#buildLockRequest(LockOptions)#lock(entity)그렇다면 그리고 당신의 협회 그리고당신의 연상이 있다 그렇다면다.cascade=lock, lazy-loading은 문제가 아닌 것도 아니야.,lazy-loading은 문제가 아닌것도 아니야.

그래서 저의 부착 법 방법과 같아 보입니다.

MyEntity attach(MyEntity entity) {
    if(getSession().contains(entity)) return entity;
    getSession().buildLockRequest(LockOptions.NONE).lock(entity);
    return entity;

초기 시험 그것은 효과가 일하는 것을 제안합니다.

아마도 그것은 약간 Eclipselink에 다른 행동한다.오래 된 데이터를 받지 않고 분리 개체 re-attach기 위해, 나는 보통: 한다.

Object obj = em.find(obj.getClass(), id);

그리고 선택적 두번째 단계(캐시가 무효화될):.

em.refresh(obj)

(entity,ReplicationMode getHibernateTemplate().replicate해 보십시오.LATEST_VERSION)

원본 포스트에서는 두가지 방법이 있긴, 원본포스트에서는 두가지 방법 있다 있다.update(obj)그리고 그리고.merge(obj)그것은 작동하지만 반대 상황에서 거론되고 있다.그것은 작동하지만 반대 상황에서 거론되고 있다.만약 이것이 정말 사실일까 개체가 이미는 이번 임시 국회에서 최우선이 그렇다면 왜 안 그런지 시험한 다음 만약 이것이 정말 사실일까 개체가 이미는 이번 임시 국회에서 최우선이 그렇다면 왜 안 그런지 시험,다음을 호출합니다 전화해 보고 싶습니다.보고 싶어요.update(obj)그렇다면, 그렇지 않으면 그렇다면,그렇지 않으면 전화.merge(obj).

는 이번 임시 국회에서 삶을 위해 테스트하는 것은 존재를위한회기에서 테스트가 있다.session.contains(obj). 따라서, 저는 다음과 같은 pseudo-code 할 거:생각할 것입니다.따라서,저는다음과 같은할 거:생각할 것입니다 의사 코드.

if (session.contains(obj))
{
    session.update(obj);
}
else 
{
    session.merge(obj);
}

이 개체를 다시 연결하면 merge()를 사용해야 합니다.

이 methode 당신의 실체 있는 변수에서 실체와 다시 로드 데이터베이스에서 부착하게 된다 다시를 표합니다.

Example :
    Lot objAttach = em.merge(oldObjDetached);
    objAttach.setEtat(...);
    em.persist(objAttach);

첫번째 merge()(지속적인 인스턴스를 업데이트할)를 호출하면,(LockMode을 잠그다NONE) (to attach the current instance, not the one returned by merge()) seems to work for some use cases.

속성 소유물hibernate.allow_refresh_detached_entity나를 위해 그 속임수 했다.나를 위해 그속임수 했다.하지만 이것은 일반적인 규칙, 어느 경우에 한해서 그것을 하고 싶어서 그것은 매우 적합하지 않다.하지만이것은 일반적인 규칙, 어느 경우에 한해서 그것을 하고 싶어서 그것은 매우 적합하지 않다.나는 그것이 도움이 되길 바랍니다.나는 그것이 도움이되길 바랍니다.

최대 절전 모드 5.4.9에 시험된

SessionFactoryOptionsBuilder

try getHibernateTemplate().saveOrUpdate()

참조URL:https://stackoverflow.com/questions/912659/what-is-the-proper-way-to-re-attach-detached-objects-in-hibernate

반응형