Я создаю веб-приложение с Spring и JPA, поддерживаемое Hibernate 4.3.6 для настойчивости. Некоторые предпосылки: результаты работы хранятся в репозитории, и контролер ResultsController проверяет их. В интерфейсе используется длительный опрос, поэтому ResultsController создает объект DeferredResult и затем отжимает поток, чтобы периодически проверять завершение задания, чтобы он мог заполнить отложенный результат и вызвать ответ.Исключая объект JPA из сохранения HibernateContext кэширования?
private DeferredResultsResponse getResults(String idString, String runType, boolean returnOnNotDone) {
String userId = userService.getCurrentUser();
// Some basic checks; is the ID a valid format, etc. Not relevant,
// but the "response" variable is set if we find a problem
final DeferredResultsResponse deferredResult = new DeferredResultsResponse(runId, runType, userId, returnOnNotDone);
if (response != null) {
deferredResult.setResult(response);
} else {
Thread t = new Thread(() -> completeResult(deferredResult));
t.run();
}
return deferredResult;
}
private void completeResult(final DeferredResultsResponse result) {
final ResultsIdentifier id = new ResultsIdentifier(result.getJobId(), result.getRunType());
int attemptCount = 0;
boolean returnOnUnfinished = result.isReturnOnUnfinished();
while (!result.hasResult() && attemptCount < MAX_ATTEMPTS) {
attemptCount++;
// ------- Problem line: -----------
Optional<JobStatus> statusMaybe = jobStatusService.get(new ResultsIdentifier(result.getJobId(), result.getRunType()));
if (!statusMaybe.isPresent()) {
result.setResult(new ResultsResponse(null, false, null, "Unable to find job status entry."));
continue;
}
JobStatus status = statusMaybe.get();
// Incomplete job cases: sleep or respond "not done" based on the flag
if (!status.isComplete() && returnOnUnfinished) {
result.setResult(new ResultsResponse(false, false, null, null));
continue;
} else if (!status.isComplete()) {
sleep();
continue;
}
// Cases of completion: respond based on success
// Various business logic of processing results
}
if (!result.hasResult()) {
result.setResult(new ResultsResponse(true, false, null, String.format("Time out after %d checks", MAX_ATTEMPTS)));
}
}
Вопрос заключается в: запрос на линии Проблема не всегда сообщать об изменениях в состоянии задания. После того, как я посмотрел, я проследил это до глубин Hibernate. В SessionImpl есть поле типа StatefulPersistenceContext, и оно хранит копию объекта JobStatus с момента его вытаскивания из базы данных. Затем он повторно использует эту копию для всех последующих запросов в том же сеансе.
Теперь я понимаю, что могу решить эту проблему, получив текущую сессию и вызвав clear() или обновив (статус). Тем не менее, для меня, чтобы оттянуть занавес JPA и использовать материал Hibernate напрямую, когда повсюду он опосредуется через репозитории Spring/JPA, это плохая форма. Итак, есть ли способ разметки XML-файла ORM, чтобы исключить кеширование определенного типа в PersistentContext?
Для справки, здесь JobStatus.xml:
<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm http://java.sun.com/xml/ns/persistence/orm_2_0.xsd"
version="2.0">
<entity class="project.model.JobStatus">
<attributes>
<embedded-id name="jobIdentifier" />
<basic name="complete" optional="false" />
<basic name="userId" optional="false" />
<basic name="successful" optional="true" />
<basic name="message" optional="true" />
<basic name="lastUpdateTime" optional="false">
<temporal>TIMESTAMP</temporal>
</basic>
</attributes>
</entity>
</entity-mappings>
jobIdentifier является, который не содержит ничего, кроме одного элемента без детей.
Кроме того, здесь JobStatusService с транзакционными аннотациями:
public interface JobStatusService {
/**
* Retrieve the statuses of all jobs for the current user.
* @return All jobs' statuses
*/
@Transactional(readOnly = true)
Iterable<JobStatus> getAllByUser();
/**
* Retrieve the status of a particular job
* @param identifier the combined job ID and type
* @return The persisted job status
*/
@Transactional(readOnly = true, propagation = Propagation.REQUIRES_NEW)
Optional<JobStatus> get(ResultsIdentifier identifier);
/**
* Save the passed status, subbing in the current user's ID if none is set,
* and updating the "last updated" time
* @param status the job status object
* @return The persisted status object
*/
@Transactional(readOnly = false)
@Modifying
JobStatus save(JobStatus status);
/**
* Delete the status of a particular job
* @param identifier the combined job ID and type
*/
@Transactional(readOnly = false)
@Modifying
void remove(ResultsIdentifier identifier);
/**
* Remove all stored job statuses for the given user id.
* @param userId User id
*/
@Transactional(readOnly = false)
@Modifying
void clearByUser(String userId);
FWIW, который не является файлом «hbm». Это «orm.xml», часть JPA. –
Правда! Извините, парень, который начал проект, изначально назвал их всеми * .hbm.xml, и я не потрудился менять имена, несмотря на то, что он был там, в xmlns. – DVA