На данный момент у нас есть класс, который выглядит примерно так (удалены обезличенные и ненужные части):
@Entity
@Table(name = "MAIN_TABLE")
public class MainTable extends AbstractTable {
@OneToMany(fetch = FetchType.LAZY, mappedBy = "mainTable")
@OrderBy("CREATED_ON DESC")
private Set<MainTableState> states;
...
public MainTableState getActiveState(){
if(this.states == null || this.states.isEmpty()){
return null;
}
MainTableState latest = states.iterator().next();
// The reason we use this for-loop, even though we have the @OrderBy annotation,
// Is because we can later add states to this list, which aren't automatically ordered
for(MainTableState state : states){
if(state.getCreatedOn() != null && latest.getCreatedOn() != null &&
state.getCreatedOn().after(latest.getCreatedOn()){
latest = state;
}
}
return latest;
}
...
}
Таким образом, в настоящее время он будет извлекать все MainTableState из БД по умолчанию, и если нам нужно активное состояние, мы используем метод for-loop. Очевидно, что это очень плохо для производительности. В настоящее время мы вообще не используем этот список (цель состояла в том, чтобы иметь историю состояний, но это было отложено на будущее), но мы довольно часто используем метод getActiveState()
, в основном для отображения строки внутри MainTableState
-класс в пользовательском интерфейсе.
Кроме того, даже если бы мы всегда использовали TreeSet
и сохраняли бы его отсортированным, поэтому нам не понадобится цикл, а вместо этого нужен только states.iterator().next()
, он все равно будет инициализировать список состояний. После тщательного тестирования производительности у нас было более 1 миллиона MainTableState
-экземпляров, когда он рухнул с ошибкой java.lang.OutOfMemoryError: GC overhead limit exceeded
.
Итак, мы хотим изменить его на следующее:
@Entity
@Table(name = "MAIN_TABLE")
public class MainTable extends AbstractEntity {
@???
private MainTableState activeState;
...
public MainTableStates getActiveState(){
return activeState;
}
...
}
Итак, мой вопрос, что я должен поставить на @???
, чтобы добиться этого? Я предполагаю, что мне нужен @Formula
или что-то подобное, но как я могу сказать, что для перехода в спящий режим он должен возвращать объект MainTableState
? Я видел, как @Formula
используется с MAX
для даты, но это должно было получить это свойство даты, а не получить весь объект на основе этой максимальной даты.
По предложению @user2447161 я использовал аннотацию @Where
, которая действительно помогает уменьшить размер коллекции до 1 (иногда), но у меня есть еще два связанных вопроса:
Как использовать
@OnToMany
и@Where
, но получить один объект вместо списка объектов единичного размера? Это вообще возможно? Здесь в ответе от декабря 2010 г. указано, что это не так. . Это было исправлено где-то за последние шесть лет?Как быть со случайным псевдонимом в предложении where? Я мог бы сделать что-то вроде этого:
@OneToMany(fetch = FetchType.LAZY, mappedBy = "mainTable") @Where(clause = "CREATED_ON = (SELECT MAX(mts.CREATED_ON) FROM MAIN_TABLE_STATES mts WHERE mts.FK_MAIN_ID = ???.MAIN_ID)") private Установить состояния ; // TODO Получить один объект вместо коллекции размером 1
Проблема в том, что ???
— это случайный псевдоним, сгенерированный hibernate (иногда это this_
, иногда что-то вроде mainTable_1_
и т. д.). Как установить этот псевдоним для всего запроса к БД, чтобы использовать его здесь? Я также попробовал вместо этого MAIN_TABLE.MAIN_ID
, который не работает, и без псевдонима он также не работает, потому что он использует псевдоним MainTableState
вместо псевдонима MainTable
(как показано ниже).
from
MAIN_TABLE this_
left outer join
MAIN_TABLE_STATUSES mainstat2_
on this_.main_id=mainstat2_.fk_main_id
and (
mainstat2_.created_on = (
SELECT
MAX(mts.created_on)
FROM
MAIN_TABLE_STATUSES mts
WHERE
-- mainstat2_.main_id should be this_.main_id instead here:
mts.fk_main_id = mainstat2_.main_id
)
)
java.lang.OutOfMemoryError: GC overhead limit exceeded
с более чем 1 миллиономMainTableState
-экземпляров. Это основная причина, по которой мы хотим сохранить только одно активное состояние, а не целые коллекции (которые в настоящее время не используются). - person Kevin Cruijssen   schedule 03.02.2017