我正在使用Spring批处理,执行批处理作业时会收到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(FilterChainProxy.java:331) 在org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:200)处 在org.springframework.security.web.FilterChainProxy $ VirtualFilterChain.doFilter(FilterChainProxy.java:331) 在org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116) 在org.springframework.security.web.FilterChainProxy $ VirtualFilterChain.doFilter(FilterChainProxy.java:331) 在org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:66) 在org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) 在org.springframework.security.web.FilterChainProxy $ VirtualFilterChain.doFilter(FilterChainProxy.java:331) 在org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105) 在org.springframework.security.web.FilterChainProxy $ VirtualFilterChain.doFilter(FilterChainProxy.java:331) 在org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56)处 在org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) 在org.springframework.security.web.FilterChainProxy $ VirtualFilterChain.doFilter(FilterChainProxy.java:331) 在org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:214) 在org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:177) 在org.springframework.web.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.handleRequest(FilterHandler.java:85) 在io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62) 在io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36) 在org.wildfly.extension.undertow.security.SecurityContextAssociationHandler.handleRequest(SecurityContextAssociationHandler.java:78)处 在io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43) 在io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:131) 在io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57) 在io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43) 在io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46) 在io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:64) 在io.undertow.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.extension.undertow.security.jacc.JACCContextIdHandler.handleRequest(JACCContextIdHandler.java:61)处 在io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43) 在io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43) 在io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:282) 在io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:261) 在io.undertow.servlet.handlers.ServletInitialHandler.access $ 000(ServletInitialHandler.java:80) 在io.undertow.servlet.handlers.ServletInitialHandler $ 1.handleRequest(ServletInitialHandler.java:172) 在io.undertow.server.Connectors.executeRootHandler(Connectors.java:199) 在io.undertow.server.HttpServerExchange $ 1.run(HttpServerExchange.java:774) 在java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) 在java.util.concurrent.ThreadPoolExecutor $ Worker.run(ThreadPoolExecutor.java:617) 在java.lang.Thread.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) 在org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:377) 在org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:461) 在org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:277) 在org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96) 在org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) 在org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java: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(本机方法)处 在sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 在sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 在java.lang.reflect.Method.invoke(Method.java:498) 在org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) 在org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:133) 在org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:97) 在org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827) 在org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.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
答案 0 :(得分:0)
您可以将JobRepositoryFactoryBean中的隔离级别更改为默认值:
@Bean
public JobRepository jobRepository() throws Exception {
JobRepositoryFactoryBean jobRepositoryFactoryBean = new JobRepositoryFactoryBean();
jobRepositoryFactoryBean.setDataSource(dataSource());
jobRepositoryFactoryBean.setTransactionManager(transactionManager());
jobRepositoryFactoryBean.setIsolationLevelForCreate("ISOLATION_DEFAULT");
return jobRepositoryFactoryBean.getObject();
}