Я пытался решить эту проблему сам и гуглить решение онлайн, но я все еще не понимаю, как это исправить. Пожалуйста, помогите!
На моем веб-сайте Spring Framework у меня есть очень трудоемкая служба (GroupSearchServiceImpl
), которая запрашивает базу данных MySQL и сохраняет ее результаты в HttpSession
. Я хочу иметь возможность отменить эту услугу и запустить ее снова с новыми параметрами. Иногда работает, но время от времени выдает java.lang.IllegalStateException: Session/EntityManager is closed
. Смотрите вывод журнала в конце этого поста.
Вот подробности (я пропустил некоторый код):
Контроллер:
@Controller
public class GroupSearchController {
private Future<Void> asyncResult;
@RequestMapping(value = "/submission/{submissionId:\\d+}/group_search/", method =
RequestMethod.POST)
public ModelAndView groupSearch(@PathVariable("submissionId") final long submissionId, final
HttpSession session, final Model model, @Valid final
FilterForm form, final Errors errors) {
if (errors.hasErrors()) {
return new ModelAndView("submission/group_search");
}
Submission submission = submissionService.findSubmission(submissionId);
// Cancel previous task if running
if (asyncResult != null) {
asyncResult.cancel(true);
}
// Run group search
asyncResult = groupSearchService.groupSearch(submission, session, form.getSpecies(), form.getSource(), form.getDisease(), new AtomicBoolean(true));
return new ModelAndView("submission/group_search");
}
}
Служба:
@Service
public class GroupSearchServiceImpl implements GroupSearchService {
@Override
@Async
@Transactional(propagation = Propagation.REQUIRED)
public Future<Void> groupSearch(Submission submission, HttpSession session, String species, String source, String disease,
AtomicBoolean running) {
LOGGER.info(String.format("Group search is started on thread %s (species: %s, source: %s, disease: %s)",
Thread.currentThread().getName(),
species != null ? species : "all",
source != null ? source : "all",
disease != null ? disease : "all"));
for (File file : submission.getFiles()) {
if (Thread.currentThread().isInterrupted()) break;
List<Spectrum> querySpectra = file.getSpectra();
for (Spectrum querySpectrum : querySpectra) {
if (Thread.currentThread().isInterrupted()) break;
List<SpectrumClusterView> clusters = MappingUtils.toList(
spectrumRepository.searchConsensusSpectra(
querySpectrum, 0.25, 0.01, species, source, disease));
}
}
if (Thread.currentThread().isInterrupted())
LOGGER.info(String.format("Group search is cancelled on thread %s (species: %s, source: %s, disease: %s)",
Thread.currentThread().getName(),
species != null ? species : "all",
source != null ? source : "all",
disease != null ? disease : "all"));
return new AsyncResult<>(null);
}
}
Репозиторий:
public class SpectrumRepositoryImpl implements SpectrumRepositoryCustom {
@PersistenceContext
private EntityManager entityManager;
@Override
public Iterable<SpectrumClusterView> searchConsensusSpectra(
Spectrum querySpectrum, double scoreThreshold, double mzTolerance,
String species, String source, String disease) {
List<SpectrumClusterView> resultList =
entityManager.createNativeQuery("SOME SQL QUERY",
SpectrumClusterView.class).getResultList();
return resultList;
}
}
Конфигурация:
@Configuration
@EnableAsync
@EnableTransactionManagement(mode = AdviceMode.PROXY, proxyTargetClass = false)
@EnableJpaRepositories(basePackages = "org.dulab.adapcompounddb.site.repositories",
entityManagerFactoryRef = "entityManagerFactoryBean", transactionManagerRef = "jpaTransactionManager")
@ComponentScan(basePackages = {"org.dulab.adapcompounddb.site", "org.dulab.adapcompounddb.rest"},
excludeFilters = @ComponentScan.Filter({Controller.class, ControllerAdvice.class}))
@Import({WebSecurityConfiguration.class})
public class ApplicationContextConfiguration {
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean() {
final HibernateJpaVendorAdapter adapter = new HibernateJpaVendorAdapter();
adapter.setDatabasePlatform("org.hibernate.dialect.MySQL5InnoDBDialect");
final LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setJpaVendorAdapter(adapter);
factory.setDataSource(dataSource);
factory.setPackagesToScan("org.dulab.adapcompounddb.models.entities");
factory.setSharedCacheMode(SharedCacheMode.ENABLE_SELECTIVE);
factory.setValidationMode(ValidationMode.NONE);
final Map<String, Object> jpaPropertyMap = new HashMap<>();
jpaPropertyMap.put("javax.persistence.schema-generation.database.action", "none");
jpaPropertyMap.put("hibernate.order_by.default_null_ordering", "last");
jpaPropertyMap.put("hibernate.enable_lazy_load_no_trans", true);
factory.setJpaPropertyMap(jpaPropertyMap);
return factory;
}
}
И, наконец, вывод журнала:
14:45:55.863 [SimpleAsyncTaskExecutor-1] INFO org.dulab.adapcompounddb.site.services.GroupSearchServiceImpl: Group search is started on thread SimpleAsyncTaskExecutor-1 (species: all, source: all, disease: all)
14:46:33.920 [SimpleAsyncTaskExecutor-2] INFO org.dulab.adapcompounddb.site.services.GroupSearchServiceImpl: Group search is started on thread SimpleAsyncTaskExecutor-2 (species: human, source: all, disease: all)
14:46:49.948 [SimpleAsyncTaskExecutor-1] INFO org.dulab.adapcompounddb.site.services.GroupSearchServiceImpl: Group search is cancelled on thread SimpleAsyncTaskExecutor-1 (species: all, source: all, disease: all)
14:47:07.991 [SimpleAsyncTaskExecutor-3] INFO org.dulab.adapcompounddb.site.services.GroupSearchServiceImpl: Group search is started on thread SimpleAsyncTaskExecutor-3 (species: human, source: ileum, disease: all)
14:47:12.903 [SimpleAsyncTaskExecutor-2] INFO org.dulab.adapcompounddb.site.services.GroupSearchServiceImpl: Group search is cancelled on thread SimpleAsyncTaskExecutor-2 (species: human, source: all, disease: all)
14:47:31.822 [SimpleAsyncTaskExecutor-4] INFO org.dulab.adapcompounddb.site.services.GroupSearchServiceImpl: Group search is started on thread SimpleAsyncTaskExecutor-4 (species: all, source: ileum, disease: all)
14:47:31.871 [SimpleAsyncTaskExecutor-4] ERROR org.dulab.adapcompounddb.site.services.GroupSearchServiceImpl: Error during the group search on thread SimpleAsyncTaskExecutor-4 (species: all, source: ileum, disease: all): Session/EntityManager is closed
java.lang.IllegalStateException: Session/EntityManager is closed
Итак, когда я отмена SimpleAsyncTaskExecutor-3
, затем SimpleAsyncTaskExecutor-4
выдает исключение java.lang.IllegalStateException: Session/EntityManager is closed
, я не понимаю, почему и как это исправить.
ОБНОВЛЕНИЕ: я установил максимальный размер пула исполнителя потока для 1, и это, кажется, помогло.
@Bean
public Executor threadPoolTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(1);
return executor;
}