[java] 최대 절전 모드에서 서로 다른 저장 방법의 차이점은 무엇입니까?

Hibernate는 어떤 식 으로든 객체를 가져 와서 데이터베이스에 넣는 소수의 메소드를 가지고 있습니다. 그들 사이의 차이점, 사용시기, 사용시기를 아는 하나의 지능적인 방법이없는 이유는 무엇입니까?

지금까지 확인한 방법은 다음과 같습니다.

  • save()
  • update()
  • saveOrUpdate()
  • saveOrUpdateCopy()
  • merge()
  • persist()


답변

여기 방법에 대한 이해가 있습니다. 실제로 이것들은 모두 실제로 사용하지는 않지만 주로 API를 기반으로합니다 .

saveOrUpdate
일부 확인에 따라 저장 또는 업데이트를 호출합니다. 예를 들어 식별자가 없으면 save가 호출됩니다. 그렇지 않으면 업데이트가 호출됩니다.

저장
엔티티를 유지합니다. 존재하지 않는 식별자를 할당합니다. 그렇다면 업데이트를 수행하는 것입니다. 엔티티의 생성 된 ID를 리턴합니다.

update
기존 식별자를 사용하여 엔터티를 유지하려고 시도합니다. 식별자가 없으면 예외가 발생했다고 생각합니다.

saveOrUpdateCopy
더 이상 사용되지 않으며 더 이상 사용해서는 안됩니다. 대신에 …

병합
이제 여기가 내 지식이 왜곡되기 시작합니다. 여기서 중요한 것은 일시적인 엔티티, 분리 된 엔티티 및 영구적 엔티티의 차이점입니다. 객체 상태에 대한 자세한 내용은 은 여기를 참조하십시오 . 저장 및 업데이트를 통해 영구 객체를 처리합니다. 그것들은 세션에 연결되어 있으므로 Hibernate는 무엇이 바뀌 었는지 알 수 있습니다. 그러나 일시적인 객체가 있으면 세션이 없습니다. 이 경우 업데이트를 위해 병합을 사용하고 저장을 위해 지속해야합니다.

persist
위에서 언급했듯이 이것은 일시적인 객체에서 사용됩니다. 생성 된 ID는 반환하지 않습니다.


답변

╔══════════════╦═══════════════════════════════╦════════════════════════════════╗
    METHOD                TRANSIENT                      DETACHED            
╠══════════════╬═══════════════════════════════╬════════════════════════════════╣
                     sets id if doesn't         sets new id even if object   
    save()         exist, persists to db,        already has it, persists    
                  returns attached object     to DB, returns attached object 
╠══════════════╬═══════════════════════════════╬════════════════════════════════╣
                     sets id on object                    throws             
   persist()       persists object to DB            PersistenceException     
                                                                             
╠══════════════╬═══════════════════════════════╬════════════════════════════════╣
                                                                             
   update()              Exception                persists and reattaches    
                                                                             
╠══════════════╬═══════════════════════════════╬════════════════════════════════╣
                copy the state of object in      copy the state of obj in    
    merge()        DB, doesn't attach it,    ║      DB, doesn't attach it,    
                  returns attached object         returns attached object    
╠══════════════╬═══════════════════════════════╬════════════════════════════════╣
                                                                             
saveOrUpdate()║           as save()                       as update()         
                                                                             
╚══════════════╩═══════════════════════════════╩════════════════════════════════╝


답변

  • persist와 save의 미묘한 차이점에 대한 설명은 Hibernate 포럼 을 참조하십시오 . 차이점은 INSERT 문이 궁극적으로 실행되는 시간과 같습니다. save 는 식별자를 반환 하므로 INSERT 문은 트랜잭션 상태에 관계없이 즉시 실행되어야합니다 (일반적으로 나쁜 것임). Persist 는 식별자를 할당하기 위해 현재 실행중인 트랜잭션 이외의 명령문을 실행하지 않습니다. 저장 / 지속은 둘 다 임시 인스턴스 , 즉 아직 식별자가 할당되지 않은 인스턴스에서 작동하며 DB에 저장되지 않습니다.

  • 업데이트병합분리 된 인스턴스 , 즉 DB에 해당 항목이 있지만 현재 세션에 연결되지 않았거나 세션에 의해 관리되지 않는 인스턴스 에서 작동합니다 . 그들 사이의 차이점은 함수에 전달되는 인스턴스에서 발생하는 것입니다. 업데이트 가 인스턴스를 다시 연결하려고 시도합니다. 즉, 세션에 연결된 영구 엔터티의 다른 인스턴스가 없어야합니다. 그렇지 않으면 예외가 발생합니다. 그러나 merge 는 모든 값을 Session의 영구 인스턴스에 복사합니다 (현재로드되지 않은 경우로드 됨). 입력 객체는 변경되지 않습니다. 그래서 병합 보다 더 일반적이며 갱신더 많은 리소스를 사용할 수 있습니다.


답변

이 링크는 다음과 같이 잘 설명되어 있습니다.

http://www.stevideter.com/2008/12/07/saveorupdate-versus-merge-in-hibernate/

우리 모두는 가끔 우리가 그 문제를 다시 볼 때 우리가이 문제를 해결했다는 것을 알지만 그 방법을 기억할 수 없을 정도로 자주 발생하는 문제를 가지고 있습니다.

Hibernate에서 Session.saveOrUpdate ()를 사용할 때 발생하는 NonUniqueObjectException은 내 것 중 하나입니다. 복잡한 응용 프로그램에 새로운 기능을 추가하겠습니다. 모든 단위 테스트가 정상적으로 작동합니다. 그런 다음 UI를 테스트하면서 객체를 저장하려고 할 때 “동일한 식별자 값을 가진 다른 객체가 이미 세션과 연결되어 있습니다.”라는 메시지와 함께 예외가 발생하기 시작합니다. 다음은 Hibernate를 사용한 Java Persistence의 코드 예제입니다.

            Session session = sessionFactory1.openSession();
            Transaction tx = session.beginTransaction();
            Item item = (Item) session.get(Item.class, new Long(1234));
            tx.commit();
            session.close(); // end of first session, item is detached

            item.getId(); // The database identity is "1234"
            item.setDescription("my new description");
            Session session2 = sessionFactory.openSession();
            Transaction tx2 = session2.beginTransaction();
            Item item2 = (Item) session2.get(Item.class, new Long(1234));
            session2.update(item); // Throws NonUniqueObjectException
            tx2.commit();
            session2.close();

이 예외의 원인을 이해하려면 분리 된 객체와 분리 된 객체에서 saveOrUpdate () 또는 update ()를 호출 할 때 발생하는 상황을 이해하는 것이 중요합니다.

개별 최대 절전 모드 세션을 닫으면 작업중인 영구 객체가 분리됩니다. 이는 데이터가 여전히 응용 프로그램의 메모리에 있지만 최대 절전 모드는 더 이상 개체의 변경 내용을 추적하지 않습니다.

분리 된 객체를 수정하고 업데이트하려면 객체를 다시 연결해야합니다. 다시 연결하는 과정에서 최대 절전 모드는 동일한 객체의 다른 사본이 있는지 확인합니다. 그것이 발견되면“실제”사본이 더 이상 무엇인지 모른다는 것을 알려 주어야합니다. 아마도 우리가 저장 될 것으로 예상되는 다른 사본들에 다른 변경이 있었지만, Hibernate는 당시에 관리하지 않았기 때문에 그것들에 대해 알지 못했습니다.

잘못된 데이터를 저장하는 대신, Hibernate는 NonUniqueObjectException을 통해 문제에 대해 알려줍니다.

그래서 우리는 무엇을해야합니까? 최대 절전 모드 3에는 merge ()가 있습니다 (Hibernate 2에서는 saveOrUpdateCopy () 사용). 이 방법을 사용하면 Hibernate는 분리 된 다른 인스턴스의 변경 사항을 저장하려는 인스턴스로 복사하여 저장하기 전에 메모리의 모든 변경 사항을 병합합니다.

        Session session = sessionFactory1.openSession();
        Transaction tx = session.beginTransaction();
        Item item = (Item) session.get(Item.class, new Long(1234));
        tx.commit();
        session.close(); // end of first session, item is detached

        item.getId(); // The database identity is "1234"
        item.setDescription("my new description");
        Session session2 = sessionFactory.openSession();
        Transaction tx2 = session2.beginTransaction();
        Item item2 = (Item) session2.get(Item.class, new Long(1234));
        Item item3 = session2.merge(item); // Success!
        tx2.commit();
        session2.close();

병합은 새로 업데이트 된 인스턴스 버전에 대한 참조를 반환한다는 점에 유의해야합니다. 세션에 항목을 다시 첨부하지 않습니다. 인스턴스 평등 (item == item3)을 테스트하면이 경우 false를 반환합니다. 이 시점부터 item3으로 작업하고 싶을 것입니다.

또한 JPA (Java Persistence API)에는 분리 및 재 부착 된 오브젝트 개념이 없으며 EntityManager.persist () 및 EntityManager.merge ()를 사용합니다.

나는 일반적으로 Hibernate를 사용할 때 saveOrUpdate ()가 내 요구에 충분하다는 것을 알았습니다. 일반적으로 같은 유형의 객체에 대한 참조를 가질 수있는 객체가있는 경우에만 병합을 사용해야합니다. 가장 최근에 예외의 원인은 코드가 참조가 재귀하지 않았 음을 확인하는 것입니다. 유효성 검사의 일부로 세션에 동일한 객체를로드하여 오류가 발생했습니다.

이 문제가 어디에서 발생 했습니까? 병합이 효과가 있었습니까 아니면 다른 솔루션이 필요 했습니까? 항상 병합을 사용하거나 특정 경우에만 필요에 따라 병합을 선호합니까


답변

실제로 최대 절전 모드 save()persist()메서드 의 차이점 은 사용중인 생성기 클래스에 따라 다릅니다.

제너레이터 클래스가 할당 된 경우 save()persist() 메소드 간에 차이가 없습니다 . 생성자 ‘할당 됨’은 프로그래머로서 데이터베이스에 저장할 기본 키 값을 제공해야합니다. [이 생성기 개념을 알고 싶습니다.] 지정된 생성자 클래스가 아닌 경우 생성기 클래스 이름이 증가 평균 인 경우를 가정하십시오. 최대 절전 모드 자체는 기본 키 ID 값을 할당 된 생성기 이외의 데이터베이스에 기본 키 ID 값을 할당합니다 (기본 키 ID 값을 기억하는 데에만 사용되는 최대 절전 모드).이 경우 우리가 호출 save()하거나 persist()메소드를 호출 하면 레코드를 삽입합니다 데이터베이스는 정상적으로 들리지만, save()메서드는 최대 절전 모드에서 생성 된 기본 키 ID 값을 반환 할 수 있습니다.

long s = session.save(k);

이 경우 persist()클라이언트에게 어떠한 가치도 돌려주지 않습니다.


답변

모든 최대 절전 모드 저장 방법의 차이점을 보여주는 좋은 예를 찾았습니다.

http://www.journaldev.com/3481/hibernate-session-merge-vs-update-save-saveorupdate-persist-example

간단히 말하면 위의 링크에 따르면

저장()

  • 트랜잭션 외부에서이 메소드를 호출 할 수 있습니다. 트랜잭션없이 이것을 사용하고 엔터티간에 계단식이있는 경우 세션을 비우지 않으면 기본 엔터티 만 저장됩니다.
  • 따라서 기본 객체에서 매핑 된 다른 객체가 있으면 트랜잭션을 커밋 할 때 또는 세션을 플러시 할 때 저장됩니다.

persist ()

  • 트랜잭션에서 save ()를 사용하는 것과 유사하므로 계단식 객체를 안전하게 처리합니다.

saveOrUpdate ()

  • 트랜잭션과 함께 또는 트랜잭션없이 사용할 수 있으며, 트랜잭션없이 사용 된 경우 save ()와 마찬가지로 매핑 된 엔터티는 저장되지 않으며 세션을 플러시합니다.

  • 제공된 데이터를 기반으로 쿼리를 삽입 또는 업데이트합니다. 데이터베이스에 데이터가 있으면 업데이트 쿼리가 실행됩니다.

최신 정보()

  • 엔터티 정보 만 업데이트한다는 것을 알고있는 경우에는 최대 절전 모드 업데이트를 사용해야합니다. 이 작업은 엔터티 개체를 영구 컨텍스트에 추가하고 트랜잭션이 커밋 될 때 추가 변경 내용을 추적하고 저장합니다.
  • 따라서 update를 호출 한 후에도 엔티티에 값을 설정하면 트랜잭션이 커밋 될 때 업데이트됩니다.

병합 ()

  • 최대 절전 모드 병합을 사용하여 기존 값을 업데이트 할 수 있지만이 메서드는 전달 된 엔터티 개체에서 복사본을 만들어 반환합니다. 리턴 된 오브젝트는 지속적 컨텍스트의 일부이며 변경 사항을 추적하며 전달 된 오브젝트는 추적되지 않습니다. 이것은 다른 모든 메소드와 merge ()의 주요 차이점입니다.

또한 이러한 모든 예제는 위에서 언급 한 링크를 참조하십시오.이 모든 다른 방법에 대한 예제를 보여줍니다.


답변

이 기사 에서 설명했듯이 대부분의 경우 JPA 방법과 update일괄 처리 작업을 선호해야 합니다.

JPA 또는 최대 절전 모드 엔티티는 다음 네 가지 상태 중 하나 일 수 있습니다.

  • 과도 (신규)
  • 관리 형 (영구적)
  • 분리
  • 삭제 (삭제)

한 상태에서 다른 상태로의 전환은 EntityManager 또는 Session 메소드를 통해 수행됩니다.

예를 들어, JPA EntityManager는 다음 엔티티 상태 전환 방법을 제공합니다.

여기에 이미지 설명을 입력하십시오

최대 절전 모드 Session모두 구현 JPA의 EntityManager방법과 같은 일부 추가 엔티티 상태 전환 방법을 제공하고 save, saveOrUpdate그리고 update.

여기에 이미지 설명을 입력하십시오

지속

엔티티 상태를 일시적 (신규)에서 관리 됨 (지속됨) 으로 변경하기 위해 Hibernate에 의해 상속 된 persistJPA EntityManager가 제공 하는 방법을 사용할 수 있습니다 Session.

persist메소드 PersistEventDefaultPersistEventListenerHibernate 이벤트 리스너 가 처리 하는를 트리거합니다 .

따라서 다음 테스트 케이스를 실행할 때 :

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

    entityManager.persist(book);

    LOGGER.info(
        "Persisting the Book entity with the id: {}",
        book.getId()
    );
});

최대 절전 모드는 다음 SQL 문을 생성합니다.

CALL NEXT VALUE FOR hibernate_sequence

-- Persisting the Book entity with the id: 1

INSERT INTO book (
    author,
    isbn,
    title,
    id
)
VALUES (
    'Vlad Mihalcea',
    '978-9730228236',
    'High-Performance Java Persistence',
    1
)

가 알 id부착 이전에 할당 된 Book현재의 지속성 콘텍스트 엔티티. 관리되는 엔터티는 Map키가 엔터티 유형과 식별자로 구성되고 값이 엔터티 참조 인 구조에 저장되기 때문에 필요합니다 . 이것이 JPA EntityManager와 최대 절전 모드 Session가 1 차 캐시라고 알려진 이유 입니다.

를 호출 할 때 persist엔티티는 현재 실행중인 지속성 컨텍스트에만 연결되며 INSERT flush는 호출 될 때까지 연기 될 수 있습니다 .

엔터티 식별자를 얻을 수있는 유일한 방법이므로 INSERT를 즉시 트리거 하는 IDENTITY 생성기 는 예외입니다 . 이러한 이유로 인해 최대 절전 모드에서는 IDENTITY 생성기를 사용하여 엔터티에 대한 삽입을 일괄 처리 할 수 ​​없습니다. 이 주제에 대한 자세한 내용은 이 기사를 확인 하십시오 .

저장

Hibernate 고유의 save방법은 JPA보다 이전 버전이며 Hibernate 프로젝트가 시작된 이후부터 사용 가능합니다.

save메소드 SaveOrUpdateEventDefaultSaveOrUpdateEventListenerHibernate 이벤트 리스너 가 처리 하는를 트리거합니다 . 따라서이 save방법은 updatesaveOrUpdate방법 과 동일 합니다.

save방법의 작동 방식 을 보려면 다음 테스트 사례를 고려하십시오.

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

    Session session = entityManager.unwrap(Session.class);

    Long id = (Long) session.save(book);

    LOGGER.info(
        "Saving the Book entity with the id: {}",
        id
    );
});

위의 테스트 케이스를 실행할 때 Hibernate는 다음 SQL 문을 생성합니다.

CALL NEXT VALUE FOR hibernate_sequence

-- Saving the Book entity with the id: 1

INSERT INTO book (
    author,
    isbn,
    title,
    id
)
VALUES (
    'Vlad Mihalcea',
    '978-9730228236',
    'High-Performance Java Persistence',
    1
)

보다시피 결과는 persist메소드 호출 과 동일합니다 . 그러나, 달리 persistsave방법은 개체 식별자를 반환합니다.

자세한 내용은 이 기사를 확인 하십시오 .

최신 정보

최대 절전 모드 특정 update방법은 더티 검사 메커니즘 을 무시 하고 플러시시 엔터티를 강제로 업데이트하기위한 것입니다.

update메소드 SaveOrUpdateEventDefaultSaveOrUpdateEventListenerHibernate 이벤트 리스너 가 처리 하는를 트리거합니다 . 따라서이 update방법은 savesaveOrUpdate방법 과 동일 합니다.

update메소드의 작동 방식 을 보려면 Book한 트랜잭션에서 엔티티 를 유지하는 다음 예제를 고려하여 엔티티가 분리 된 상태 인 동안이를 수정하고 update메소드 호출을 사용하여 SQL UPDATE를 강제 실행합니다 .

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

    entityManager.persist(book);

    return book;
});

LOGGER.info("Modifying the Book entity");

_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");
});

위의 테스트 케이스를 실행할 때 Hibernate는 다음 SQL 문을 생성합니다.

CALL NEXT VALUE FOR hibernate_sequence

INSERT INTO book (
    author,
    isbn,
    title,
    id
)
VALUES (
    'Vlad Mihalcea',
    '978-9730228236',
    'High-Performance Java Persistence',
    1
)

-- Modifying the Book entity
-- Updating the Book entity

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

는 것을 알 UPDATE직전 커밋, 지속성 컨텍스트 플러시 동안 실행되며, 그 이유의 Updating the Book entity메시지가 처음 기록됩니다.

@SelectBeforeUpdate불필요한 업데이트를 피하기 위해 사용

이제 분리 상태에있는 동안 엔터티가 변경되지 않은 경우에도 UPDATE가 항상 실행됩니다. 이를 방지하기 위해 @SelectBeforeUpdateHibernate 어노테이션을 사용하면 SELECT페치 loaded state된 명령문 이 트리거 되어 더티 점검 메커니즘에서 사용됩니다.

따라서 주석으로 Book엔티티에 주석을 달면 @SelectBeforeUpdate:

@Entity(name = "Book")
@Table(name = "book")
@SelectBeforeUpdate
public class Book {

    //Code omitted for brevity
}

다음 테스트 케이스를 실행하십시오.

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

    entityManager.persist(book);

    return book;
});

doInJPA(entityManager -> {
    Session session = entityManager.unwrap(Session.class);

    session.update(_book);
});

최대 절전 모드는 다음 SQL 문을 실행합니다.

INSERT INTO book (
    author,
    isbn,
    title,
    id
)
VALUES (
    'Vlad Mihalcea',
    '978-9730228236',
    'High-Performance Java Persistence',
    1
)

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

이번에 UPDATE는 Hibernate 더티 검사 메커니즘이 엔티티가 수정되지 않았 음을 감지했기 때문에 실행되지 않습니다.

저장 또는 업데이트

Hibernate 고유의 saveOrUpdate메소드는 saveand 의 별명 일뿐 update입니다.

saveOrUpdate메소드 SaveOrUpdateEventDefaultSaveOrUpdateEventListenerHibernate 이벤트 리스너 가 처리 하는를 트리거합니다 . 따라서이 update방법은 savesaveOrUpdate방법 과 동일 합니다.

이제 saveOrUpdate엔티티를 유지하거나 UPDATE다음 예제에서 설명 하는 것처럼 강제로 사용 하려고 할 때 사용할 수 있습니다 .

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");

doInJPA(entityManager -> {
    Session session = entityManager.unwrap(Session.class);
    session.saveOrUpdate(_book);
});

조심 NonUniqueObjectException

save, update에서 발생할 수있는 한 가지 문제 saveOrUpdate는 지속성 컨텍스트에 이미 다음 예제에서와 동일한 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
    );
}

이제 위의 테스트 케이스를 실행할 때 Hibernate는 NonUniqueObjectException두 번째에 EntityManager이미 Book전달한 것과 동일한 식별자를 가진 엔티티를 포함 update하고 Persistence Context가 동일한 엔티티의 두 표현을 보유 할 수 없기 때문에 a를 던질 것 입니다.

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)

병합

를 피하려면 JPA에서 제공 하고 최대 절전 모드에서 상속 한 방법 NonUniqueObjectException을 사용해야합니다 .mergeEntityManagerSession

설명한 바와 같이 ,이 문서 는이 merge엔터티 참조 영속 컨텍스트에서 발견가 있는지 데이터베이스로부터 새로운 엔티티 스냅 샷을 인출하고, 분리 된 엔티티를 복사 상태는로 전달 merge하는 방법.

merge메소드 MergeEventDefaultMergeEventListenerHibernate 이벤트 리스너 가 처리 하는를 트리거합니다 .

merge방법의 작동 방식 을 확인하기 위해 Book하나의 트랜잭션에서 엔티티 를 유지하는 다음 예제를 고려하여 엔티티가 분리 된 상태에있는 동안이를 수정하고 분리 된 엔티티를 merge서브 시퀀스 지속성 컨텍스트에 전달하십시오 .

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

    entityManager.persist(book);

    return book;
});

LOGGER.info("Modifying the Book entity");

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

doInJPA(entityManager -> {
    Book book = entityManager.merge(_book);

    LOGGER.info("Merging the Book entity");

    assertFalse(book == _book);
});

위의 테스트 케이스를 실행할 때 Hibernate는 다음 SQL 문을 실행했습니다.

INSERT INTO book (
    author,
    isbn,
    title,
    id
)
VALUES (
    'Vlad Mihalcea',
    '978-9730228236',
    'High-Performance Java Persistence',
    1
)

-- Modifying the Book entity

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

에 의해 리턴 된 엔티티 참조 mergemerge메소드에 전달 된 분리 된 참조 와 다릅니다 .

merge분리 된 엔티티 상태를 복사 할 때 JPA를 사용하는 것을 선호하지만 SELECT배치 처리 태스크를 실행할 때 추가 로 문제가 될 수 있습니다.

update따라서 현재 실행중인 지속성 컨텍스트에 이미 연결된 엔티티 참조가없고 분리 된 엔티티가 수정 된 경우 사용을 선호해야합니다 .

이 주제에 대한 자세한 내용은 이 기사를 확인 하십시오 .

결론

엔터티를 유지하려면 JPA persist방법을 사용해야합니다 . 분리 된 엔티티 상태를 복사하려면 merge선호해야합니다. 이 update방법은 일괄 처리 작업에만 유용합니다. savesaveOrUpdate단지 별칭 update당신은 아마 전혀 사용하지합니다.

일부 개발자 save는 엔터티가 이미 관리되는 경우에도 호출 하지만 관리 엔터티의 경우 지속성 컨텍스트 플러시 시간에 UPDATE가 자동으로 처리되므로 실수로 중복 이벤트가 발생합니다.

자세한 내용은 이 기사를 확인 하십시오 .