Каковы различия между различными методами сохранения в Hibernate?

StackOverflow https://stackoverflow.com/questions/161224

  •  03-07-2019
  •  | 
  •  

Вопрос

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

Методы, которые я определил на данный момент:

  • save()
  • update()
  • saveOrUpdate()
  • saveOrUpdateCopy()
  • merge()
  • persist()
Это было полезно?

Решение

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

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

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

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

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

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

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

Другие советы

╔══════════════╦═══════════════════════════════╦════════════════════════════════╗
║    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.Похоже, что разница заключается во времени окончательного выполнения инструкции INSERT.С сохранять возвращает идентификатор, оператор INSERT должен выполняться мгновенно независимо от состояния транзакции (что обычно плохо). Сопротивляться не будет выполнять никаких операторов за пределами текущей транзакции только для присвоения идентификатора.Сохранить/Сохранить оба работают временные экземпляры, т.е. экземпляры, которым еще не присвоен идентификатор и поэтому они не сохраняются в БД.

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

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

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

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

Исключение NonUniqueObjectException, возникающее при использовании Session.saveOrUpdate() в Hibernate, является одним из моих.Я буду добавлять новый функционал в сложное приложение.Все мои модульные тесты работают нормально.Затем при тестировании пользовательского интерфейса, пытаясь сохранить объект, я начинаю получать исключение с сообщением «другой объект с тем же значением идентификатора уже был связан с сеансом». Вот какой -то пример кода от Java Storyence с 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().Обычно мне нужно использовать слияние только тогда, когда у меня есть объекты, которые могут ссылаться на объекты того же типа.Совсем недавно причина исключения заключалась в коде, проверяющем нерекурсивность ссылки.Я загружал тот же объект в свой сеанс в рамках проверки, что вызывало ошибку.

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

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

Если у нас назначен класс генератора, то нет никакой разницы между save() и persist() методы.Поскольку генератор «назначенный» означает, как программист, нам необходимо дать значение первичного ключа для сохранения в правой основе базы данных [надеюсь, вы знаете эту концепцию генераторов] в случае другого класса Generator, предположим, что если наше имя класса генератора является Hibernate It Self назначит значение идентификатора первичного ключа в правое значение базы данных [кроме назначенного генератора, Hibernate используется только для позаботиться о значении идентификатора первичного ключа, поэтому в этом случае, если мы вызовываем save() или persist() Метод, тогда он будет вставлять запись в базу данных обычно, но слышит, что это save() метод может вернуть значение идентификатора первичного ключа, которое генерируется спящим режимом, и мы можем увидеть его с помощью

long s = session.save(k);

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

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

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

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

сохранять()

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

сопротивляться()

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

сохранитьилиобновление()

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

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

обновлять()

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

слияние()

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

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

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

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

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

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

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

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

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

enter image description here

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

enter image description here

Сопротивляться

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

А persist метод запускает PersistEvent которым занимается DefaultPersistEventListener Прослушиватель событий спящего режима.

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

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

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

Единственным исключением является Генератор ИДЕНТИЧНОСТИ который сразу запускает INSERT, поскольку это единственный способ получить идентификатор объекта.По этой причине Hibernate не может выполнять пакетную вставку сущностей с помощью генератора IDENTITY.Более подробную информацию по этой теме см. Эта статья.

Сохранять

Специально для Hibernate save Этот метод появился раньше JPA и доступен с самого начала проекта Hibernate.

А save метод запускает SaveOrUpdateEvent которым занимается 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 Прослушиватель событий спящего режима.Следовательно update метод эквивалентен методу save и saveOrUpdate методы.

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

СохранитьИлиОбновить

Специально для Hibernate saveOrUpdate метод - это просто псевдоним для save и update.

А saveOrUpdate метод запускает SaveOrUpdateEvent которым занимается 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 Прослушиватель событий спящего режима.

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

Для более подробной информации, проверьте Эта статья.

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

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

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

НИКОГДА НЕ ИСПОЛЬЗУЙТЕ МЕТОД СОХРАНЕНИЯ в спящем режиме.ЗАБУДЬТЕ, ЧТО ОНО СУЩЕСТВУЕТ ДАЖЕ В СПИНЕ!

Сопротивляться

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

На этом этапе, если вы снова «Настойчивы», изменений не произойдет.И больше не будет сохранений, если мы попытаемся сохранить существующий объект.

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

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

Слияние против обновления

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

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

Обратите внимание на код ниже:

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-запрос выбора, например слияния.

удалить

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top