Я использую Spring Batch и получаю InvalidIsolationLevelException при выполнении пакетного задания. Работа выполнялась, когда я использовал MapJobRepositoryFactoryBean, но мне нужно создать таблицы BATCH_ * для базы данных.
В приложении уже настроен менеджер транзакций.
Моя весенняя версия - 4.3.18.RELEASE и использует Oracle SQL для базы данных.
Это моя пакетная конфигурация:
@Configuration
@ComponentScan({"com..."})
public class BatchConfig {
private static final Logger LOGGER = LoggerFactory.getLogger(BatchConfig.class);
private static final String REPORTS_STEP_NAME = "reportStep";
private static final String REPORTS_JOB_NAME = "reportsJob";
private static final int REPORTS_STEP_CHUNK_SIZE = 20;
private static final String MAX_END_DATE = "2999-12-31 00:00:00";
private static final String MAX_END_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
private static final String END_DATE_PARAM = "endDate";
private static final String REPORT_STATUS_PARAM = "reportSend";
private static final YesNo NO = new YesNo("N");
@Autowired
private ApplicationConfig applicationConfig;
@Autowired
private ReportProcessor reportProcessor;
@Autowired
private ReportItemWriter reportItemWriter;
@Bean
public JobBuilderFactory jobBuilderFactory() throws Exception {
JobBuilderFactory jobBuilderFactory = new JobBuilderFactory(jobRepository());
return jobBuilderFactory;
}
@Bean
public StepBuilderFactory stepBuilderFactory() throws Exception {
StepBuilderFactory stepBuilderFactory = new StepBuilderFactory(jobRepository(), applicationConfig.transactionManager());
return stepBuilderFactory;
}
@Bean
public PlatformTransactionManager transactionManager() {
JpaTransactionManager jpaTransactionManager = new JpaTransactionManager();
jpaTransactionManager.setDataSource(dataSource());
jpaTransactionManager.setEntityManagerFactory(applicationConfig.entityManagerFactory().getObject());
return jpaTransactionManager;
}
@Bean
public JobRegistry jobRegistry() {
return new MapJobRegistry();
}
@Bean
public JobExplorer jobExplorer() throws Exception {
JobExplorerFactoryBean jobExplorerFactoryBean = new JobExplorerFactoryBean();
jobExplorerFactoryBean.setDataSource(dataSource());
jobExplorerFactoryBean.afterPropertiesSet();
return jobExplorerFactoryBean.getObject();
}
@Bean
public JobOperator jobOperator() throws Exception {
SimpleJobOperator jobOperator = new SimpleJobOperator();
jobOperator.setJobExplorer(jobExplorer());
jobOperator.setJobRegistry(jobRegistry());
jobOperator.setJobLauncher(jobLauncher());
jobOperator.setJobRepository(jobRepository());
return jobOperator;
}
@Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("...");
dataSource.setUrl("...");
dataSource.setUsername("...");
dataSource.setPassword("...");
return dataSource;
}
@Bean
public JobRepository jobRepository() throws Exception {
JobRepositoryFactoryBean jobRepositoryFactoryBean = new JobRepositoryFactoryBean();
jobRepositoryFactoryBean.setDataSource(dataSource());
jobRepositoryFactoryBean.setTransactionManager(transactionManager());
jobRepositoryFactoryBean.setIsolationLevelForCreate("ISOLATION_SERIALIZABLE");
return jobRepositoryFactoryBean.getObject();
}
@Bean
public JobLauncher jobLauncher() throws Exception {
SimpleJobLauncher simpleJobLauncher = new SimpleJobLauncher();
simpleJobLauncher.setJobRepository(jobRepository());
return simpleJobLauncher;
}
public JpaPagingItemReader<FishingVessel> readFishingVesselRecords() throws ParseException {
LOGGER.info("Inside JpaPagingItemReader");
JpaPagingItemReader<FishingVessel> fishingVesselsReader = new JpaPagingItemReader<>();
fishingVesselsReader.setEntityManagerFactory(applicationConfig.entityManagerFactory().getObject());
fishingVesselsReader.setQueryString(FishingVessel.FISHING_VESSEL_REPORTS);
fishingVesselsReader.setTransacted(false);
fishingVesselsReader.setSaveState(false);
Map<String, Object> params = createQueryParams();
fishingVesselsReader.setParameterValues(params);
fishingVesselsReader.setPageSize(100);
return fishingVesselsReader;
}
private Map<String, Object> createQueryParams() throws ParseException {
Map<String, Object> params = new HashMap<>();
DateFormatter dateFormatter = new DateFormatter(MAX_END_DATE_FORMAT);
Date date = dateFormatter.parse(MAX_END_DATE, Locale.ENGLISH);
params.put(END_DATE_PARAM, date);
//params.put(REPORT_STATUS_PARAM, NO);
return params;
}
@Bean
public Step reportsStep() throws Exception {
DefaultTransactionAttribute attribute = new DefaultTransactionAttribute();
attribute.setPropagationBehavior(Propagation.REQUIRED.value());
attribute.setIsolationLevel(Isolation.SERIALIZABLE.value());
attribute.setTimeout(30);
return stepBuilderFactory()
.get(REPORTS_STEP_NAME)
.<FishingVessel, FishingVessel>chunk(REPORTS_STEP_CHUNK_SIZE)
.reader(readFishingVesselRecords())
.processor(reportProcessor)
.writer(reportItemWriter)
.transactionAttribute(attribute)
.build();
}
@Bean
public Job reportsJob() throws Exception {
return jobBuilderFactory()
.get(REPORTS_JOB_NAME)
.start(reportsStep())
.build();
}
}
Это конфигурация приложения, которая уже существовала в приложении:
@Configuration
@ComponentScan({
"com....components",
"com....services",
"com....converters",
"com....controllers",
"com....fluxFolder",
"com....processors",
"com....flux.service",
"com....flux.gateway"
})
@EnableJpaRepositories("com....repositories")
@EnableTransactionManagement
@EnableJpaAuditing
@EnableWebMvc
@Import({SecurityConfig.class})
@PropertySource("classpath:application.properties")
public class ApplicationConfig {
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setPersistenceXmlLocation("classpath:/META-INF/persistence.xml");
return factory;
}
@Bean
@Primary
public PlatformTransactionManager transactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
return transactionManager;
}
@Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
@Bean
public ViewResolver viewResolver() {
UrlBasedViewResolver viewResolver = new UrlBasedViewResolver();
viewResolver.setViewClass(JsfView.class);
viewResolver.setSuffix(".xhtml");
return viewResolver;
}
}
И это мой контроллер для инициализации пакетного задания:
@RestController
public class BatchController {
private static final String JOB_ID = "JobID";
private JobExecution jobExecution;
@Autowired
private JobOperator jobOperator;
@Autowired
private JobLauncher jobLauncher;
@Autowired
private Job reportsJob;
@Autowired
private JobExplorer jobExplorer;
@GetMapping("/batch/enable")
public String batchTest() throws JobParametersInvalidException, JobExecutionAlreadyRunningException, JobRestartException, JobInstanceAlreadyCompleteException {
JobParameters jobParameters = new JobParametersBuilder()
.addString(JOB_ID, String.valueOf(System.currentTimeMillis()))
.toJobParameters();
JobInstance job;
jobExecution = new JobExecution(jobLauncher.run(reportsJob, jobParameters));
return "batch job started";
}
@GetMapping("/batch/disable")
public String disable() {
String jobName = jobExecution.getJobInstance().getJobName();
Set<JobExecution> jobExecutions = jobExplorer.findRunningJobExecutions(jobName);
for (JobExecution je : jobExecutions) {
try {
jobOperator.stop(je.getId());
} catch (NoSuchJobExecutionException e) {
} catch (JobExecutionNotRunningException e) {
}
}
return jobName + " disabled.";
}
}
Это трассировка стека, которую я получаю:
14: 01: 30,945 ОШИБКА [io.undertow.request] (задание по умолчанию-1) UT005023:
Запрос на обработку исключений в /.../batch/enable: org.springframework
.web.util.NestedServletException: обработка запроса не удалась; вложенными
исключение
org.springframework.transaction.InvalidIsolationLevelException:
DefaultJpaDiale ct не поддерживает пользовательские уровни изоляции из-за
ограничения в стандарте JPA. Конкретные меры могут быть реализованы
в пользовательских вариантах JpaDialect.
в org.springframework.web.servlet.FrameworkServlet.processRequest (FrameworkServlet.java:982)
в org.springframework.web.servlet.FrameworkServlet.doGet (FrameworkServlet.java:861)
на javax.servlet.http.HttpServlet.service (HttpServlet.java:687)
в org.springframework.web.servlet.FrameworkServlet.service (FrameworkServlet.java:846)
на javax.servlet.http.HttpServlet.service (HttpServlet.java:790)
в io.undertow.servlet.handlers.ServletHandler.handleRequest (ServletHandler.java:86)
в io.undertow.servlet.handlers.FilterHandler $ FilterChainImpl.doFilter (FilterHandler.java:130)
в org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal (CharacterEncodingFilter.java:197)
в org.springframework.web.filter.OncePerRequestFilter.doFilter (OncePerRequestFilter.java:107)
в io.undertow.servlet.core.ManagedFilter.doFilter (ManagedFilter.java:60)
в io.undertow.servlet.handlers.FilterHandler $ FilterChainImpl.doFilter (FilterHandler.java:132)
в org.springframework.security.web.FilterChainProxy $ VirtualFilterChain.doFilter (FilterChainProxy.java:317)
в org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke (FilterSecurityInterceptor.java:127)
в org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter (FilterSecurityInterceptor.java:91)
в org.springframework.security.web.FilterChainProxy $ VirtualFilterChain.doFilter (FilterChainProxy.java:331)
в org.springframework.security.web.access.ExceptionTranslationFilter.doFilter (ExceptionTranslationFilter.java:114)
в org.springframework.security.web.FilterChainProxy $ VirtualFilterChain.doFilter (FilterChainProxy.java:331)
в org.springframework.security.web.session.SessionManagementFilter.doFilter (SessionManagementFilter.java:137)
в org.springframework.security.web.FilterChainProxy $ VirtualFilterChain.doFilter (FilterChainProxy.java:331)
в org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter (AnonymousAuthenticationFilter.java:111)
в org.springframework.security.web.FilterChainProxy $ VirtualFilterChain.doFilter (FilterChainProxy.java:331)
в org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter (SecurityContextHolderAwareRequestFilter.java:170)
в org.springframework.security.web.FilterChainProxy $ VirtualFilterChain.doFilter (FilterChainProxy.java:331)
в org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter (RequestCacheAwareFilter.java:63)
в org.springframework.security.web.FilterChainProxy $ VirtualFilterChain.doFilter (FilterChainProxy.java:331)по адресу org.springframework.security.web.session.ConcurrentSessionFilter.doFilter (ConcurrentSessionFilter.java:155) по адресу org.springframework.security.web.FilterChainProxy $ VirtualFilterChain.doFilter (FilterChain.swe.f..authentication.AbstractAuthenticationProcessingFilter.(LogoutFilter.java:116) в org.springframework.security.web.FilterChainProxy $ VirtualFilterChain.doFilter (FilterChainProxy.java:331) в org.springframework.security.web.header.HeaderWriterFilterF ():org.springframework.web.filter.OncePerRequestFilter.doFilter (OncePerRequestFilter.java:107) в org.springframework.security.web.FilterChainProxy $ VirtualFilterChain.doFilter (FilterChainProxy.j)rg.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter (SecurityContextPersistenceFilter.java:105) в org.springframework.security.web.FilterChainProxy $ VirtualFilterChain.doFilwork.pr.j.context.request.async.WebAsyncManagerIntegrationFilter.FilterChainProxy.java:331) в org.springframework.security.web.FilterChainProxy.doFilterInternal (FilterChainProxy.java:214) в org.springframework.security.web.FilterChainProxy.doFilter (FilterChag.pr).filter.DelegatingFilterProxy.invokeDelegate (DelegatingFilterProxy.java:347) в org.springframework.web.filter.DelegatingFilterProxy.doFilter (DelegatingFilterProxy.java:263) в io.undertow.servlet.core.ManagedFilter.doFilter (ManagedFilter.java:60) в io.undertow.servlet.handlers.FilterHandler $ FilterChainImpl.doFilter (FilterHandler.java:132) в io.undertow.servlet.handlers.FilterHandler.handleRequlerj85: FilterH:по адресу io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest (ServletSecurityRoleHandler.java:62) по адресу io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest.SecurityContextAssociationHandler.) в io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest (ServletAuthenticationCallHandler.java:57) в io.undertow.server.handlers.PredicateHandler.handleRequest (PredicateateHandler.java!.security.handlers.AuthenticationMechanismsHandler.handleRequest (AuthenticationMechanismsHandler.java:58) при io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest (CachedAuthenticatedSessionHandler.java:72) в io.undertow.security.handlers.NotificationReceiverHandler.handleRequest (NotificationReceiverHandler.java: 50)в io.undertow.security.handlers.SecurityInitialHandler.handleRequest (SecurityInitialHandler.java:76) в io.undertow.server.handlers.PredicateHandler.handleRequest (PredicateHandler.java:43) в org.wildfly.curity.JACCContextIdHandler.handleRequest (JACCContextIdHandler.java:61) в io.undertow.server.handlers.PredicateHandler.handleRequest (PredicateHandler.java:43) в io.undertow.io.undertow.(ServletInitialHandler.java:80) в io.undertow.servlet.handlers.ServletInitialHandler $ 1.handleRequest (ServletInitialHandler.java:172) в io.undertow.server.Connectors.executeRootHandler (Connectors.java.er:.HttpServerExchange $ 1.выполнить (HttpServerExchange.java:774) в java.util.concurrent.ThreadPoolExecutor.runWorker (ThreadPoolExecutor.java:1142) в java.util.concurrent.ThreadPoolExecutor $ Worker.run (ThreadPoolExecutor.java.java6: 6: 6).run (Thread.java:748) Причина: org.springframework.transaction.InvalidIsolationLevelException: DefaultJpaDialect не поддерживает пользовательские уровни изоляции из-за ограничений в стандартном JPA.Конкретные меры могут быть реализованы в пользовательских вариантах JpaDialect.в org.springframework.orm.jpa.DefaultJpaDialect.beginTransaction (DefaultJpaDialect.java:63) в org.springframework.orm.jpa.JpaTransactionManager.doBegin (JpaTransactionManager.java:380.ranschange.transgram.su) в org.spring(AbstractPlatformTransactionManager.java:377) в org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNeeded (TransactionAspectSupport.java:461) в org.springframework.transaction.interceptor.pport.WransInservice.Transaction.action.interceptor.TransactionInterceptor.invoke (TransactionInterceptor.java:96) в org.springframework.aop.framework.ReflectiveMethodInvocation.proceed (ReflectiveMethodInvocation.java:179) в org.springframeworkk.213) на com.sun.proxy. $ Proxy419.getLastJobExecution (Неизвестный источник) на org.springframework.batch.core.launch.support.SimpleJobLauncher.run (SimpleJobLauncher.java:98) в com .... controllers.BatchController.batchTest (BatchController.java:42) в sun.reflect.NativeMethodAccessorImpl.invoke0 (собственный метод) в мотиве восстановления.invoke (NativeMethodAccessorImpl.java:62) на солнцеsupport.InvocableHandlerMethod.invokeAndHandle (ServletInvocableHandlerMethod.java:97) в org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod (RequestMappingHandlerAdapter.jworkqu.we..HandlerAdapter.handleInternal (RequestMappingHandlerAdapter.java:738)в org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle (AbstractHandlerMethodAdapter.java:85)
в org.springframework.web.servlet.DispatcherServlet.doDispatch (DispatcherServlet.java:967)
в org.springframework.web.servlet.DispatcherServlet.doService (DispatcherServlet.java:901)
в org.springframework.web.servlet.FrameworkServlet.processRequest (FrameworkServlet.java:970)
... еще 71