У меня есть сценарий, в котором мое приложение имеет доступ к сеансу в течение ограниченных временных окон, в течение которого оно должно извлекать данные из базы данных в память, а затем использовать только данные в памяти для обслуживания запросов.
Модель данных представляет собой простую связь «один ко многим», например:
<class name="com.foo.Road" table="road">
<id name="oid" column="oid"/>
<map name="carCountMap" fetch="subselect">
<key column="road_oid" foreign-key="oid"/>
<index column="time_oid" type="long" />
<one-to-many class="com.foo.CarCount" />
</map>
<map name="truckCountMap" fetch="subselect">
<key column="road_oid" foreign-key="oid"/>
<index column="time_oid" type="long" />
<one-to-many class="com.foo.TruckCount" />
</map>
</class>
Теперь предположим, что данные о количестве легковых и грузовых автомобилей существуют в течение нескольких лет, что намного больше, чем может поместиться в памяти.Кроме того, я действительно заинтересован только в том, чтобы загрузить счетчики автомобилей за последние 3 месяца.
Мой вопрос заключается в том, каков наилучший способ загрузки этих данных с использованием режима гибернации, например:
- road.getCarCountMap () возвращает набор только для подсчета количества автомобилей за последние 3 месяца (может быть пустым)
- Я не получаю какой-то сумасшедший декартово произведение, для обработки которого требуются века
- Нет
LazyInitializationException
s выдается после закрытия сессии
Некоторые вещи, которые я пробовал:
1. Сделать carCountMap
collection eager и укажите атрибут where
в отображении, например:
<map name="carCountMap" fetch="subselect" lazy="false" where="time_oid > 1000">
(аналогично truckCountMap
)
Это лучше всего соответствует семантике сбора, которую я хочу,но, к сожалению, это заставляет меня жестко кодировать значение, поэтому я не могу ссылаться на последние 3 месяца.time_oid
увеличивается на 1 каждый день.
2. Определите карты как ленивые и используйте hql-запрос, чтобы вручную объединить 3 таблицы:
from Road r
left outer join fetch r.carCountMap ccm
left outer join fetch r.truckCoutnMap tcm
where (ccm.time.oid > :startDate)
or (tcm.time.oid > :startDate)
ПроблемаЭто означает, что полученный запрос возвращает несколько миллионов строк, в то время как это должно быть 10 тыс. дорог * 4 измерения в месяц (еженедельно) * 3 месяца = ~ 120 тыс.Этот запрос завершается примерно через час, что нелепо, поскольку подход № 1 (который загружает те же данные, что и я) завершается за 3 минуты.
3. Определитьотображаются как ленивые и загружают дороги сначала с критериями, а затем запускают дополнительные запросы, чтобы заполнить коллекцию
List roadList = session.createCriteria(Road.class).list();
session.getNamedQuery("fetchCcm").setLong("startDate", startDate).list();
session.getNamedQuery("fetchTcm").setLong("startDate", startDate).list();
return roadList;
Это запускает правильные запросы, но полученные подсчеты легковых и грузовых автомобилей не привязываются кRoad
объектов в roadList
.Поэтому, когда я пытаюсь получить доступ к счетчикам на любом объекте Road, я получаю LazyInitializationException
.
4. Определить карты как ленивые, используйте criteria.list()
для загрузки всех дорог, итерируйте повсе даты измерений за последние 3 месяца, поэтому принудительно загрузите эти значения.
Я еще не пробовал, потому что это звучит очень неуклюже, и я не уверен, что избавится от LazyInitializationException
- Есть ли обходные пути для проблем, с которыми я столкнулся при использовании этих методов?
- Есть ли вообще лучший метод?