Проблема с методом поиска в режиме гибернации

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

  •  23-09-2019
  •  | 
  •  

Вопрос

Обновить:ПРИМЕР ДЛЯ ПОЯСНЕНИЯ Я собираюсь привести пример того, что происходит, просто чтобы прояснить ситуацию в моем приложении 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 в противном случае.
  • Другой просто создает прокси-сервер с правильным идентификатором, не обращаясь сразу к базе данных, и обработает его по мере необходимости в последующих операциях (возможно, при сбросе).

Кажется, вы используете второй вариант, может быть, вы могли бы попробовать первый и посмотреть, решит ли это вашу проблему?

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