Я изо всех сил пытаюсь «обновить» объект (Foo), который выглядит так:
public class Foo {
//...
@OneToMany(mappedBy = "fooRef", fetch = FetchType.LAZY)
private List<Bar> bars;
}
public class Bar {
//...
@Column(name = "FOO_ID")
private Long fooRef;
@Column(name = "STATE")
@Enumerated(EnumType.STRING)
private State state;
}
Как Spring JPA не реализует метод обновления, я просто снова запрашиваю объект. Это код, который не работает, и я не знаю почему:
for(int i=0; i<MAX_RETRIES; i++) {
List<Bar> bars = foo.getBars();
// check bars state
if (someBarIsBad) {
try {
TimeUnit.SECONDS.sleep(delay);
} catch (InterruptedException ignored) {
}
} else {
break;
}
foo = fooRepo.findById(fooId); // "refresh"
}
Цель состоит в том, чтобы продолжить повторную попытку, пока все столбцы не достигнут желаемого состояния.
Тест, который я выполняю, помещает точку останова в последнюю инструкцию цикла, поэтому, когда она прерывается, я иду к таблице и меняю состояние всех полос на желаемое, чтобы затем выйти из цикла. Дело в том, что возвращенный foo, bars не отражает внесенные мной изменения.
Пробовал убрать сон, но проблема не в этом. Думаю, должно быть что-то с маппингом.
Я тестировал удаление LAZY fetching, но результат тот же. В любом случае, это не должно быть проблемой, поскольку я извлекаю bars с тем же прицелом, что и foo. Что ты имеешь в виду под sout? Это метод jpa?
nonono, sout - это ярлык для System.out.println(). Удаление выборки некорректно, причина для отношения OneToMany - тип выборки по умолчанию LAZY. Так что это удаление ничего не меняет. Попробуйте изменить выборку с LAZY на EAGER. И да, вы правы - область действия такая же, но разница в прямом и непрямом использовании таблицы сущностей Bar.
Это действительно странно. Я пробовал с eagger fetch, ничего. Я пробовал напрямую получить barRepo.findByFooRef, но ничего. И я уже уверяю, что вношу изменения напрямую с помощью коммита.




Скорее всего, это связано с тем, что все выполняется в рамках одной транзакции. Это заставляет JPA не перезагружать объект из базы данных, а возвращать тот, который у него уже есть в сеансе.
Либо убедитесь, что вы находитесь в новой транзакции при каждом «обновлении», либо исключите объект из сеанса, чтобы он снова перезагружался.
Имеет смысл. Но я не уверен, как мне изолировать транзакцию. Я взял fooRepo.findById(fooId) и обернул его методом, аннотированным @Transactional. Все еще не возвращает мне обновленную версию.
Важная часть заключается в том, что код, который вы показали в своем вопросе, НЕ заключен в метод, аннотированный @Transactional.
Я сделал, и код выше, и getFoo(ID) являются транзакционными. Все тот же :(
Ладно, я понял. Я не знал об уровнях изоляции. IN с аннотациями get FooD) с @Transactional(readOnly = true, isolation = Isolation.REPEATABLE_READ)
Предполагаю, что проблема в
fetch = FetchType.LAZY.barsбудет обновлен, когда вы попытаетесь их использовать. Попробуйте сделать что-то подобное после обновленияfor (Bar bar : foo.getBars()) { sout(bar);}. Надеюсь, это вызовет ленивую инициализацию.