Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Java EE (J2EE) и Spring > Hibernate проблемы с кешем


Автор: pnd_ku 30.3.2009, 16:41
Всем добрый вечер!
Суть проблемы следующая:
есть 2 POJO объекта и с соотношением один-ко-многим..

процесс такой: 
1)извлекается набор родителей
2)потом к одному из родителей добавляется детёныш (smile)
3)заново извлекаеца набор родителей.. в этом наборе, при запросе детёнышей у конкретного родителя к которому добавляли, новый не появляется

мои подозрения падают на кеш и на флаш сессии.. но флаш отрабатывает нармально, то есть после добавления детёныша в набор он сразу же отображаеца в базе

собственно маппинги:

родитель

Код

<hibernate-mapping>
  <class catalog="doctor" name="VOs.AvailableSlot" table="AvailableSlots">
    <id name="id" type="java.lang.Integer">
      <column name="ID"/>
      <generator class="identity"/>
    </id>
    <many-to-one class="VOs.Therapiest" column="therapiestId" lazy="no-proxy" name="therapiest" not-null="true"/>
    <property name="dateTime" type="timestamp">
      <column length="19" name="dateTime" not-null="true"/>
    </property>
    <property name="availableSlots" type="byte">
      <column name="availableSlots" not-null="true"/>
    </property>
    <property name="comment" type="string">
      <column length="65535" name="comment" not-null="true"/>
    </property>
    <property name="colorFg" type="string">
      <column length="6" name="colorFG" not-null="true"/>
    </property>
    <property name="colorBg" type="string">
      <column length="6" name="colorBG" not-null="true"/>
    </property>
    <set lazy="true" name="bookings">
      <key column="slotID"/>
      <one-to-many class="VOs.Booking"/>
    </set>
  </class>
</hibernate-mapping>



детёныш

Код

<hibernate-mapping>
  <class catalog="doctor" name="VOs.Booking" table="Bookings">
    <id name="id" type="java.lang.Integer">
      <column name="ID"/>
      <generator class="identity"/>
    </id>
    <many-to-one class="VOs.AvailableSlot" column="slotId" lazy="no-proxy" name="availableSlot" not-null="true"/>
    <many-to-one class="VOs.Patient" column="patientID" lazy="no-proxy" name="patient" not-null="true"/>
    <property name="status" type="byte">
      <column name="status" not-null="true"/>
    </property>
    <property name="payedValue" type="float">
      <column name="payedValue" not-null="true" precision="12" scale="0"/>
    </property>
    <property name="comment" type="string">
      <column length="65535" name="comment" not-null="true"/>
    </property>
  </class>
</hibernate-mapping>



куда хоть копнуть? спасиба!  smile 

Автор: pnd_ku 30.3.2009, 17:10
Уфф.. обнаружил проблему..
теперь интересно услышать объяснение от опытных - как так получилось

вот тест кейз:

Код

//показать информацию о слотах и заказах
        List slots = MainDAO.getAvailableSlotsDAO().getAll();
        for(Object o: slots) {
            AvailableSlot slot = (AvailableSlot) o;
            System.out.println("==== " + slot.getId());
            Set bookings = slot.getBookings();
            System.out.println("- " + bookings.size());
            System.out.println();
        }

//создать новый заказ для слота
        AvailableSlot currentSlot = MainDAO.getAvailableSlotsDAO().get(15);

        Booking booking = new Booking();
        booking.setAvailableSlot(currentSlot);
        booking.setPatient(MainDAO.getPatientsDAO().get(1));
        booking.setPayedValue(0);
        booking.setStatus(new Byte("0"));
        booking.setComment("");

        MainDAO.getBookingsDAO().save(booking);

        currentSlot.getBookings().add(booking);
        MainDAO.getAvailableSlotsDAO().save(currentSlot);
        

        System.out.println("------------------------------------- ");

//показать опять
        slots = MainDAO.getAvailableSlotsDAO().getAll();
        for(Object o: slots) {
            AvailableSlot slot = (AvailableSlot) o;
            System.out.println("==== " + slot.getId());
            Set bookings = slot.getBookings();
            System.out.println("- " + bookings.size());
            System.out.println();
        }


Всё решилось добавлением вот этих двух строк

currentSlot.getBookings().add(booking);
MainDAO.getAvailableSlotsDAO().save(currentSlot);

Нет, ну понятно что новый заказ для слоиа нужно сохранить. Но зачем его ручками добавлять в коллекцию этому слоту?
Слоты извлекаюца второй раз заново, как указать Hibernat`у  что нужно заново извлечь и заказы?

Автор: MisterCleric 31.3.2009, 09:14
Здравствуй. Я скажу такое:
это издержки Object Relation Mapping. Это в базе все просто: сказали в Bookings форинг кей на AvailableSlots и механизмами реляционности новые записи становятся известны. JAVA - это же не данные, а только объекты. Так что если надо что бы один объект знал о другом, то ему насильно надо об этом сообщить.
От сюда делаем разбор твоего размышления
Цитата

1)извлекается набор родителей
2)потом к одному из родителей добавляется детёныш (smile)
3)заново извлекаеца набор родителей.. в этом наборе, при запросе детёнышей у конкретного родителя к которому добавляли, новый не появляется


Вроде как бы все правильно. Но тут я уверен, что все эти операции производились в рамках одной Session. Т.е. первый раз набор родителей извлекался все-таки из базы. Операция инсерта тоже пошла в базу. Ну а вот последняя операция не пошла в базу. Так как сработал "кеш первого уровня"

Цитата

 <set lazy="true" name="bookings">
      <key column="slotID"/>
      <one-to-many class="VOs.Booking"/>
    </set>


Нужно lazy="false", если вдруг ты закроешь Session, а потом тебе понадобится коллекция bookings. Т.е. доставать коллекцию "детеныешей" насильно.
Цитата

currentSlot.getBookings().add(booking);
MainDAO.getAvailableSlotsDAO().save(currentSlot);


можно было и без добавления в коллекцию. Можно вызвать на currentSlot refresh - тогда в базу пойдет насильный запрос.

Можно и без refresh и без добавления в коллекцию. но тогда операции инсерта и дальнейшего обновления currentSlot надо делать в разных Session.
Вроде все.

Автор: pnd_ku 31.3.2009, 21:24
Цитата

Т.е. первый раз набор родителей извлекался все-таки из базы. Операция инсерта тоже пошла в базу. Ну а вот последняя операция не пошла в базу. Так как сработал "кеш первого уровня"


Первая - да, вторая тоже в базу, третья - из базы извлекались слоты, а  дочерние букинги за ними не тянулись а брались из кеша. С одной стороны понятно зачем - для улучшения производительности, с другой - всё таки странно.  smile 

Цитата

Нужно lazy="false", если вдруг ты закроешь Session, а потом тебе понадобится коллекция bookings. Т.е. доставать коллекцию "детеныешей" насильно.


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

Цитата

можно было и без добавления в коллекцию. Можно вызвать на currentSlot refresh - тогда в базу пойдет насильный запрос.


Вот это классно! спасиба, не подозревал smile Подозревал что какойто апдейт должен быть, но пошел иным путём.

Вообще огромадное спасиба за такой развёрнутый ответ! Мне очень помогло, и надеюсь ещё камунить поможет  smile 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)