Hibernate - это постоянная сущность во время сброса, когда сущность не изменилась - PullRequest
3 голосов
/ 19 мая 2010

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

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

Query qry = em.createNamedQuery("Clients.findByClientID");
qry.setParameter("clientID", clientID);

Clients client = (Clients) qry.getSingleResult();

results.setFname(client.getFirstName());
results.setLname(client.getLastName());
...
return results;

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

Причина, по которой это проблема, заключается в том, что в середине всего этого находится какой-то старый код, который вносит некоторые прямые изменения JDBC в клиент. Когда менеджер сущностей остается, изменения, сделанные прямым JDBC, теряются.

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

Может ли кто-нибудь объяснить или подтвердить поведение, которое мы наблюдаем?

Ответы [ 3 ]

2 голосов
/ 19 мая 2010

Я не знаю внутренностей зимней спячки, но я думаю, что вы правы. Но я не думаю, что hibernate сравнивается с БД, а сравнивает с локальным кешем сессии.

Вы можете избежать этой проблемы, установив для объекта значение readOnly - hibernate не проверяет изменения, например,

   session.setReadOnly(client, true);

Кроме того, вы также можете выселить объект, используя Session.evict (). В следующий раз, когда потребуется объект, он будет считан из БД, включая любые изменения, сделанные вами с помощью пользовательского JDBC.

1 голос
/ 30 июня 2010

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

1 голос
/ 19 мая 2010

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

Эта специфическая проблема укусила нас раньше и вызвала точно такие же проблемы ненужной очистки - у нас также была проблема производительности, в тесном цикле нам нужно было flush() сеанс, и каждый раз, когда мы делали сотни неизмененных объектов был сброшен обратно в БД.

В нашем случае это было то, что рассматриваемые объекты не реализовали equals() и hashCode() правильно - Hibernate, очевидно, полагается на них, чтобы проверить, изменился ли объект, и если они неверны в каком-то смысле у него нет другого выбора, кроме как сбросить их обратно.

Из памяти (это было некоторое время назад) на самом деле это была вспомогательная сущность, которая не реализовала hashCode() правильно - представьте себе отношение Student - Teacher, где Teacher неправильно реализует эти методы. При грязной проверке Student Hibernate проверяет в своем кэше сущностей Teacher, думает, что его там нет (из-за неправильных реализаций), и поэтому думает, что Student изменился, отбрасывая его обратно, чтобы выписать новый Teacher ID.

Так что проверьте hashCode() и equals() на предмет прав доступа, всех связанных с ним объектов и любых других компонентов / типов пользователей, которые записываются в БД.

...