Проблема с методом поиска в режиме гибернации
Вопрос
Обновить:ПРИМЕР ДЛЯ ПОЯСНЕНИЯ Я собираюсь привести пример того, что происходит, просто чтобы прояснить ситуацию в моем приложении Spring + Hibernate.Представьте, что у меня есть эти две сущности (предположим, что геттеры и сеттеры тоже существуют).
@Entity
public class Class1(){
private Integer id;
@OneToOne
private Class2 object2;
}
@Entity
public class Class2(){
private Integer id;
@OneToOne
private Class1 object2;
}
Итак, в моей базе данных у меня есть две таблицы для сопоставления каждого экземпляра каждого объекта.Предположим, я сохранил в базе данных эти объекты:
- Объект (класс Class1) :id = 1 , object2 = ObjectB
- ObjectB (класс Class2) :id = 2 , object2 = объект
- ObjectC (класс Class2) :id = 3 , object2 = null что означает, что A и B связаны.Предположим, теперь я хочу связать ObjectA с ObjectC.Это означает, что я тоже должен удалить ссылку в ObjectB.
Для этого я делаю следующее:
//I get the objectA from database
Class1 storedObjectA = myservice.find(objectAId);
//Now in storedObject1 I have the same as what it is stored as objectA
//I change only the object2 attribute of it
storedObject1.setObject2(objectC);
//I search again in the database to see objectA
Class1 reStoredObjectA = myservice.find(objectAId);
Восстановленный объект теперь находится:
- Восстановленный объект (class = Class1) id = 1, объект2 = ObjectC
хотя в базе данных есть:
- Восстановленный объект (class = Class1) id = 1, object2 = ObjectB
Метод find не выполнял поиск в базе данных, и я получил предыдущий поиск, хотя у меня отключены мой запрос и кэши второго уровня.Метод find переходит только в DAO, где он выполняется в EntityManager.find(Class1.class, id) Как я могу выполнить свой второй поиск find в базе данных?
Спасибо
(Полное объяснение)
Здравствуйте,
У меня есть приложение, которое использует Spring 3 и Hibernate.У меня есть объект с именем Class1, который хранится в базе данных.Эта сущность имеет единственную ссылку на другую сущность, называемую Class2.Class2 имеет еще одну ссылку OneToOne на Class1, и обе ссылки имеют уникальное свойство, равное true.
У меня есть следующий код в моем контроллере:
//I have an object called dataFromUser which is instance of Class1 and
// it is obtained via @ModelAttribute annotation from a form
Integer id = dataFromUser.getId();
//I get correctly the stored object from the database
Class1 storedData = myService.find(id); //this will call em.find of hibernate
//I set to the stored data the attribute I want to change
storedData.setObject2();
//I save again the object
myService.save(storedData);
Метод save в MyService будет использовать диспетчер сущностей для сохранения данных, но перед этим он проверит предыдущую связь между объектом Class1 и объектом Class2, чтобы удалить ее в случае, если новому объекту Class2 присвоен экземпляр Class1.По этой причине я должен снова вызвать метод find, чтобы посмотреть, что есть в моей базе данных
На Службе:
@Transactional
public void save(Class1 object1){
Class1 objectFromDB = myDAO.find(object1.getId());
// .... update the old object and save
}
Проблема в том, что objectFromDB в Сервисе не такой, как когда я делал MyService.find(id) в контроллере.Проблема в том, что он ищет его не в базе данных, а в памяти.Я знаю это, потому что при вызове второго метода find() не регистрируется оператор SQL.Поскольку я сделал setObject2() для объекта storedData, я получаю именно этот объект, когда вызываю метод find во второй раз, и база данных не содержит его, потому что он еще не был сохранен.
Я попытался отключить кэш в своей конфигурации, просто чтобы попробовать, но это все еще происходит.У меня есть ehCache с такой конфигурацией:
В persistence.xml У меня есть эти свойства (я установил значение false для обоих кэшей):
<properties>
<!-- Hibernate 3.5.0 - try org.hibernate.cache.* package -->
<property name="hibernate.cache.provider_class"
value="net.sf.ehcache.hibernate.SingletonEhCacheProvider" />
<property name="hibernate.cache.use_query_cache" value="false" />
<property name="hibernate.cache.use_second_level_cache" value="false" />
<property name="hibernate.generate_statistics" value="true" />
<property name="hibernate.cache.use_structured_entries" value="false" />
<property name="hibernate.format_sql" value="true" />
<!-- http://www.jroller.com/eyallupu/entry/hibernate_s_hbm2ddl_tool -->
<!-- create, create-drop, update, validate -->
<property name="hibernate.hbm2ddl.auto" value="update" />
</properties>
В моем ehcache.xml я установил значение 0 для maxElementsInMemory, а для overflowToDisk - значение false, чтобы отключить его тоже.
Есть ли какой-нибудь способ избежать этой ситуации?
Спасибо.
Решение 2
Хорошо, я это выясню.Проблема в том, что hibernate ищет объекты в своем сеансе перед поиском в базе данных.поэтому мне пришлось отсоединить объект от сеанса, прежде чем изменять его.Чтобы сделать это в режиме гибернации:
//being em my EntityManager instance
Session session = (Session) em.getDelegate();
session.evict(plan);
//Now the find object will not get the object wich is in session
//but the one in database
Другие советы
Я не уверен, что правильно понял, но на всякий случай ...
Есть такие два метода загрузки объекта.Существует разница, если объект не находится в текущем контексте памяти:
- Один из них наверняка обращается к базе данных, возвращает экземпляр, если он существует, или null в противном случае.
- Другой просто создает прокси-сервер с правильным идентификатором, не обращаясь сразу к базе данных, и обработает его по мере необходимости в последующих операциях (возможно, при сбросе).
Кажется, вы используете второй вариант, может быть, вы могли бы попробовать первый и посмотреть, решит ли это вашу проблему?