Каковы различия между различными методами сохранения в Hibernate? - PullRequest
195 голосов
/ 02 октября 2008

В Hibernate есть несколько методов, которые так или иначе берут ваш объект и помещают его в базу данных. Каковы различия между ними, когда использовать какой, и почему нет только одного интеллектуального метода, который знает, когда и что использовать?

Методы, которые я определил до сих пор:

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

Ответы [ 10 ]

117 голосов
/ 02 октября 2008

Вот мое понимание методов. В основном они основаны на API , хотя я не использую все это на практике.

saveOrUpdate Звонки либо сохраняются, либо обновляются в зависимости от некоторых проверок. Например. если идентификатора не существует, вызывается save. В противном случае обновление называется.

1010 * сохранить * Сохраняет сущность. Назначит идентификатор, если он не существует. Если кто-то делает, это по сути делает обновление. Возвращает сгенерированный идентификатор объекта.

обновление Попытки сохранить сущность, используя существующий идентификатор. Если идентификатора не существует, я считаю, что исключение выдается.

saveOrUpdateCopy Это устарело и больше не должно использоваться. Вместо этого есть ...

сливаться Теперь это где мои знания начинают давать сбои. Здесь важна разница между временными, обособленными и постоянными объектами. Для получения дополнительной информации о состояниях объекта, посмотрите здесь . С помощью сохранения и обновления вы имеете дело с постоянными объектами. Они связаны с сеансом, поэтому Hibernate знает, что изменилось. Но когда у вас есть временный объект, сеанс не включается. В этих случаях вам нужно использовать слияние для обновлений и сохранять для сохранения.

сохраняются Как упомянуто выше, это используется на временных объектах. Он не возвращает сгенерированный идентификатор.

114 голосов
/ 04 сентября 2013
╔══════════════╦═══════════════════════════════╦════════════════════════════════╗
║    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()         ║
║              ║                               ║                                ║
╚══════════════╩═══════════════════════════════╩════════════════════════════════╝
65 голосов
/ 02 октября 2008
  • См. Hibernate Forum для объяснения тонких различий между сохранением и сохранением. Похоже, разница в том, когда в конечном итоге выполняется оператор INSERT. Поскольку save возвращает идентификатор, оператор INSERT должен выполняться немедленно, независимо от состояния транзакции (что, как правило, плохо). Persist не будет выполнять никаких инструкций за пределами текущей выполняемой транзакции только для назначения идентификатора. Оба параметра Save / Persist работают с временными экземплярами , то есть экземплярами, которым еще не присвоен идентификатор, и поэтому они не сохраняются в БД.

  • Обновление и Объединение оба работают на отдельных экземплярах , т.е. экземплярах, которые имеют соответствующую запись в БД, но которые в настоящее время не присоединены к (или управляется) сеансом. Разница между ними заключается в том, что происходит с экземпляром, который передается функции. update пытается повторно присоединить экземпляр, это означает, что в данный момент не может быть другого экземпляра постоянного объекта, присоединенного к сеансу, в противном случае выдается исключение. merge , однако, просто копирует все значения в постоянный экземпляр в сеансе (который будет загружен, если он еще не загружен). Входной объект не изменен. Таким образом, merge является более общим, чем update , но может использовать больше ресурсов.

12 голосов
/ 11 июня 2013

Эта ссылка хорошо объясняет:

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

У всех нас есть те проблемы, с которыми мы сталкиваемся достаточно редко, поэтому, когда мы видим их снова, мы знаем, что решили это, но не можем вспомнить, как.

Исключение NonUniqueObjectException, возникающее при использовании Session.saveOrUpdate () в Hibernate, является одним из моих. Я буду добавлять новые функции в сложное приложение. Все мои юнит-тесты работают нормально. Затем, тестируя пользовательский интерфейс, пытаясь сохранить объект, я начинаю получать исключение с сообщением «другой объект с таким же значением идентификатора уже был связан с сеансом». Вот пример кода из Java Persistence с 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));
            session2.update(item); // Throws NonUniqueObjectException
            tx2.commit();
            session2.close();

Чтобы понять причину этого исключения, важно понимать отдельные объекты и то, что происходит, когда вы вызываете saveOrUpdate () (или просто update ()) для отдельного объекта.

Когда мы закрываем отдельную сессию Hibernate, постоянные объекты, с которыми мы работаем, отсоединяются. Это означает, что данные все еще находятся в памяти приложения, но Hibernate больше не отвечает за отслеживание изменений в объектах.

Если мы затем изменим наш отсоединенный объект и захотим обновить его, мы должны снова присоединить объект. Во время этого процесса присоединения Hibernate проверит, есть ли другие копии того же объекта. Если он что-то обнаружит, он должен сказать нам, что больше не знает, что такое «настоящая» копия. Возможно, другие изменения были внесены в те другие копии, которые мы ожидаем сохранить, но Hibernate не знает о них, потому что в то время не управлял ими.

Вместо сохранения, возможно, неверных данных, Hibernate сообщает нам о проблеме через исключение NonUniqueObjectException.

Так что нам делать? В Hibernate 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.

Также важно отметить, что Java Persistence API (JPA) не имеет концепции отдельных и повторно присоединенных объектов и использует EntityManager.persist () и EntityManager.merge ().

В общем я обнаружил, что при использовании Hibernate saveOrUpdate () обычно достаточно для моих нужд. Обычно мне нужно использовать слияние только тогда, когда у меня есть объекты, которые могут иметь ссылки на объекты того же типа. Совсем недавно причина исключения заключалась в коде, подтверждающем, что ссылка не была рекурсивной. Я загружал один и тот же объект в мой сеанс как часть проверки, вызывая ошибку.

Где вы столкнулись с этой проблемой? Работает ли Merge для вас или вам нужно другое решение? Вы предпочитаете всегда использовать слияние или предпочитаете использовать его только по мере необходимости для конкретных случаев

5 голосов
/ 12 апреля 2017

Я нашел хороший пример, показывающий различия между всеми способами сохранения в спящем режиме:

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

Вкратце, по вышеуказанной ссылке:

сохранить ()

  • Мы можем вызвать этот метод вне транзакции. Если мы используем это без транзакции и у нас есть каскад между сущностями, то только основная сущность будет сохранена, если мы не очистим сеанс.
  • Итак, если есть другие объекты, сопоставленные с первичным объектом, они сохраняются во время совершения транзакции или когда мы очищаем сеанс.

сохраняются ()

  • Это похоже на использование save () в транзакции, поэтому оно безопасно и заботится о любых каскадных объектах.

saveOrUpdate ()

  • Может использоваться с транзакцией или без нее, и точно так же, как save (), если она используется без транзакции, сопоставленные сущности не будут сохраняться, пока мы не очистим сеанс.

  • Результаты в запросах вставки или обновления на основе предоставленных данных. Если данные присутствуют в базе данных, выполняется запрос на обновление.

обновление ()

  • Обновление Hibernate следует использовать, если мы знаем, что мы обновляем только информацию об объектах. Эта операция добавляет объект сущности в постоянный контекст, и дальнейшие изменения отслеживаются и сохраняются при фиксации транзакции.
  • Следовательно, даже после вызова update, если мы установим какие-либо значения в сущности, они будут обновлены при фиксации транзакции.

слияния ()

  • Слияние Hibernate может использоваться для обновления существующих значений, однако этот метод создает копию из переданного объекта сущности и возвращает ее. Возвращенный объект является частью постоянного контекста и отслеживается для любых изменений, переданный объект не отслеживается. В этом основное отличие метода merge () от всех других методов.

Также для практических примеров всего этого, пожалуйста, обратитесь к ссылке, которую я упомянул выше, она показывает примеры для всех этих различных методов.

5 голосов
/ 11 апреля 2012

На самом деле разница между методами гибернации save() и persist() зависит от класса генератора, который мы используем.

Если назначен наш класс генератора, то нет разницы между save() и persist() методами. Поскольку генератор «назначен» означает, что как программисту мы должны дать значение первичного ключа для сохранения в праве базы данных [Надеюсь, вы знаете эту концепцию генератора] В случае отличного от назначенного класса генератора, предположим, что если имя нашего класса генератора равно Increment, это означает, что hibernate сам назначит значение идентификатора первичного ключа в праве базы данных [кроме назначенного генератора, hibernate используется только для того, чтобы сохранить значение идентификатора первичного ключа, запомните ], поэтому в этом случае, если мы вызовем метод save() или persist(), он будет обычно вставлять запись в базу данных. Но слышим, что метод save() может вернуть значение идентификатора первичного ключа, сгенерированное hibernate, и мы можем увидеть его по

long s = session.save(k);

В этом же случае persist() никогда не вернет клиенту никакого значения.

2 голосов
/ 27 февраля 2019

Как я объяснил в этой статье , вам следует чаще использовать методы JPA и update для задач пакетной обработки.

Объект JPA или Hibernate может находиться в одном из следующих четырех состояний:

  • Переходный (Новый)
  • Управляемый (Постоянный)
  • Отдельный
  • Удалено (удалено)

Переход из одного состояния в другое осуществляется с помощью методов EntityManager или Session.

Например, JPA EntityManager предоставляет следующие методы перехода состояний объекта.

enter image description here

Hibernate Session реализует все методы JPA EntityManager и предоставляет некоторые дополнительные методы перехода состояния объекта, такие как save, saveOrUpdate и update.

.

enter image description here

Упорство

Чтобы изменить состояние объекта с Переходного (Новое) на Управляемое (Постоянное), мы можем использовать метод persist, предлагаемый JPA EntityManager, который также наследуется Hibernate Session.

Метод persist вызывает PersistEvent, который обрабатывается прослушивателем событий DefaultPersistEventListener Hibernate.

Поэтому при выполнении следующего контрольного примера:

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()
    );
});

Hibernate генерирует следующие операторы 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 и Hibernate Session известны как кэш первого уровня.

При вызове persist сущность присоединяется только к текущему контексту персистентности, и INSERT может быть отложено до вызова flush.

Единственным исключением является генератор IDENTITY , который сразу вызывает INSERT, поскольку это единственный способ получить идентификатор сущности. По этой причине Hibernate не может выполнять пакетную вставку для сущностей, использующих генератор IDENTITY. Для более подробной информации по этой теме, прочитайте эту статью .

Сохранить

Метод save, характерный для Hibernate, предшествует JPA и доступен с начала проекта Hibernate.

Метод save вызывает SaveOrUpdateEvent, который обрабатывается прослушивателем событий Hibernate DefaultSaveOrUpdateEventListener. Следовательно, метод save эквивалентен методам update и saveOrUpdate.

Чтобы увидеть, как работает метод 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. Однако, в отличие от persist, метод save возвращает идентификатор объекта.

Для получения более подробной информации, ознакомьтесь с этой статьей .

Обновление

Специфичный для Hibernate метод update предназначен для обхода механизма грязной проверки и принудительного обновления сущности во время сброса.

Метод update запускает SaveOrUpdateEvent, который обрабатывается прослушивателем событий DefaultSaveOrUpdateEventListener Hibernate. Следовательно, метод update эквивалентен методам save и saveOrUpdate.

Чтобы увидеть, как работает метод update, рассмотрим следующий пример, в котором сущность Book сохраняется в одной транзакции, затем он изменяет ее, пока сущность находится в отсоединенном состоянии, и вызывает SQL UPDATE, используя 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, чтобы избежать ненужных обновлений

Теперь, ОБНОВЛЕНИЕ всегда будет выполняться, даже если объект не был изменен в отключенном состоянии. Чтобы предотвратить это, вы можете использовать аннотацию @SelectBeforeUpdate Hibernate, которая вызовет оператор 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);
});

Hibernate выполняет следующие операторы 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 обнаружил, что объект не был изменен.

SaveOrUpdate

Специфичный для Hibernate метод saveOrUpdate - это просто псевдоним для save и update.

Метод saveOrUpdate вызывает SaveOrUpdateEvent, который обрабатывается прослушивателем событий Hibernate DefaultSaveOrUpdateEventListener. Следовательно, метод update эквивалентен методам save и saveOrUpdate.

Теперь вы можете использовать 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, заключается в том, что контекст постоянства уже содержит ссылку на сущность с тем же идентификатором и того же типа, что и в следующем примере:

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, и Постоянный контекст не может содержать два представления одного и того же объекта.

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)

Слияние

Чтобы избежать NonUniqueObjectException, вам нужно использовать метод merge, предлагаемый JPA EntityManager и наследуемый Hibernate Session.

Как объяснено в этой статье , merge извлекает новый моментальный снимок объекта из базы данных, если в контексте постоянства не найдена ссылка на объект, и копирует состояние отдельного объекта, переданного в merge метод.

Метод merge вызывает MergeEvent, который обрабатывается прослушивателем событий DefaultMergeEventListener Hibernate.

Чтобы увидеть, как работает метод 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

Обратите внимание, что ссылка на сущность, возвращаемая merge, отличается от отсоединенной, которую мы передали методу merge.

Теперь, хотя вы предпочитаете использовать JPA merge при копировании состояния отсоединенной сущности, дополнительная SELECT может быть проблематичной при выполнении задачи пакетной обработки.

По этой причине вам следует предпочесть использовать update, если вы уверены, что к текущему контексту персистентности уже не привязана ссылка на сущность и что отсоединенная сущность была изменена.

Подробнее об этой теме читайте в этой статье .

Заключение

Чтобы сохранить сущность, вы должны использовать метод JPA persist. Чтобы скопировать состояние отсоединенного объекта, merge должно быть предпочтительным. Метод update полезен только для задач пакетной обработки. save и saveOrUpdate являются просто псевдонимами update, и вы, вероятно, не должны их использовать вообще.

Некоторые разработчики вызывают save даже тогда, когда сущность уже управляется, но это ошибка и вызывает избыточное событие, поскольку для управляемых сущностей UPDATE автоматически обрабатывается во время сброса контекста постоянства.

Для получения более подробной информации, ознакомьтесь с этой статьей .

2 голосов
/ 03 октября 2008

Имейте в виду, что если вы вызываете обновление для отдельного объекта, в базе данных всегда будет выполняться обновление независимо от того, изменили вы объект или нет. Если это не то, что вы хотите, вы должны использовать Session.lock () с LockMode.None.

Вы должны вызывать update только в том случае, если объект был изменен вне области текущего сеанса (в автономном режиме).

1 голос
/ 26 октября 2012

Ни один из следующих ответов не является правильным. Все эти методы кажутся похожими, но на практике делают совершенно разные вещи. Трудно давать короткие комментарии. Лучше дать ссылку на полную документацию об этих методах: http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html/objectstate.html

0 голосов
/ 22 ноября 2018

Ни один из ответов выше не является полным. Хотя ответ Лео Теобальда выглядит ближайшим ответом.

Суть в том, как hibernate работает с состояниями сущностей и как он обрабатывает их при изменении состояния. Все должно быть рассмотрено и в отношении сбросов и фиксаций, которые, кажется, все полностью проигнорировали.

НИКОГДА НЕ ИСПОЛЬЗУЙТЕ ЭКОНОМИЧНЫЙ МЕТОД HIBERNATE. ЗАБУДЬТЕ, ЧТО ЭТО ДАЖЕ СУЩЕСТВУЕТ В HIBERNATE!

Упорство

Как все объяснили, Persist в основном переводит сущность из "переходного" состояния в "управляемое" состояние. На этом этапе слякоть или фиксация могут создать оператор вставки. Но сущность все равно останется в «Управляемом» состоянии. Это не меняется с флешем.

В этот момент, если вы снова будете "Упорствовать", изменений не будет. И больше не будет спасений, если мы попытаемся сохранить существующую сущность.

Веселье начинается, когда мы пытаемся выселить сущность.

Выселение - это специальная функция Hibernate, которая переводит сущность из «Управляемого» в «Отделенный». Мы не можем вызвать упорство на отдельном объекте. Если мы это сделаем, то Hibernate создаст исключение, и вся транзакция будет откатана при фиксации.

Слияние с обновлением

Это две интересные функции, выполняющие разные задачи, когда рассматриваются по-разному. Они оба пытаются перевести сущность из состояния «Отключено» в состояние «Управляемый». Но делать это по-другому.

Поймите факт, что Detached означает своего рода "автономное" состояние. и управляемый означает состояние "Онлайн".

Соблюдайте код ниже:

Session ses1 = sessionFactory.openSession();

    Transaction tx1 = ses1.beginTransaction();

    HibEntity entity = getHibEntity();

    ses1.persist(entity);
    ses1.evict(entity);

    ses1.merge(entity);

    ses1.delete(entity);

    tx1.commit();

Когда вы это сделаете? Как ты думаешь, что произойдет? Если вы сказали, что это вызовет исключение, то вы правы. Это вызовет исключение, потому что, слияние сработало на объекте объекта, который является отделенным состоянием. Но это не меняет состояния объекта.

За сценой слияние вызовет запрос на выборку и в основном возвращает копию объекта, который находится в прикрепленном состоянии. Соблюдайте код ниже:

Session ses1 = sessionFactory.openSession();

    Transaction tx1 = ses1.beginTransaction();
    HibEntity entity = getHibEntity();

    ses1.persist(entity);
    ses1.evict(entity);

    HibEntity copied = (HibEntity)ses1.merge(entity);
    ses1.delete(copied);

    tx1.commit();

Приведенный выше пример работает, потому что слияние принесло новую сущность в контекст, который находится в постоянном состоянии.

При применении с обновлением то же самое работает нормально, потому что обновление на самом деле не приносит копию объекта, как слияние.

Session ses1 = sessionFactory.openSession();

    Transaction tx1 = ses1.beginTransaction();

    HibEntity entity = getHibEntity();

    ses1.persist(entity);
    ses1.evict(entity);

    ses1.update(entity);

    ses1.delete(entity);

    tx1.commit();

В то же время в трассировке отладки мы видим, что Update не вызывал SQL-запрос select как merge.

удалить

В приведенном выше примере я использовал удаление, не говоря об удалении. Удаление в основном переводит объект из управляемого состояния в состояние «удалено». И при сбросе или подтверждении выдаст команду удаления для сохранения.

Однако можно вернуть сущность в «управляемое» состояние из «удаленного» состояния, используя метод persist.

Надеюсь, приведенное выше объяснение прояснило любые сомнения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...