java - Spring Hibernate 5.4.22.Final:javax.persistence.TransactionRequiredException:升级spring boot时没有事务正在进行
问题描述
我最近从 spring boot 1.5 更新到 2.3.5,但是在持久化数据时遇到了一些问题。我的应用程序是 spring batch,它读取、处理和写入数据到数据库、读取器和处理器都很好,但是编写器给出了问题。它适用于 1.5 spring boot 版本。以下是简要代码:
BatchScheduler.Class
import org.springframework.batch.core.launch.support.SimpleJobLauncher;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean;
import org.springframework.batch.support.transaction.ResourcelessTransactionManager;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.annotation.EnableScheduling;
//@Configuration
@EnableScheduling
public class BatchScheduler {
@Bean
public ResourcelessTransactionManager transactionManager() {
return new ResourcelessTransactionManager();
}
@Bean
public MapJobRepositoryFactoryBean mapJobRepositoryFactory(
ResourcelessTransactionManager txManager) throws Exception {
MapJobRepositoryFactoryBean factory = new MapJobRepositoryFactoryBean(txManager);
factory.afterPropertiesSet();
return factory;
}
@Bean
public JobRepository jobRepository(MapJobRepositoryFactoryBean factory) throws Exception {
return factory.getObject();
}
@Bean
public SimpleJobLauncher jobLauncher(JobRepository jobRepository) {
SimpleJobLauncher launcher = new SimpleJobLauncher();
launcher.setJobRepository(jobRepository);
return launcher;
}
}
@Configuration
@EnableBatchProcessing
@Import({BatchScheduler.class})
public class LogBatchConfiguration {
private static final Logger log = LoggerFactory.getLogger(LogBatchConfiguration.class);
@Autowired private SimpleJobLauncher jobLauncher;
@Autowired
@Qualifier(value = "mainDataSource")
public DataSource mainDataSource;
@Autowired
@Qualifier(value = "toolsDataSource")
public DataSource toolsDataSource;
@Autowired public StepBuilderFactory stepBuilderFactory;
@Autowired public JobBuilderFactory jobBuilderFactory;
@Autowired private RestTemplate restTemplate;
@Qualifier(value = "createLocalSessionFactory")
@Autowired
private SessionFactory createLocalSessionFactory;
@Qualifier(value = "createToolSessionFactory")
@Autowired
private SessionFactory createToolSessionFactory;
@Bean
RestTemplate restTemplate(RestTemplateBuilder builder) {
RestTemplate restTemplate = new RestTemplate();
List<HttpMessageConverter<?>> converters = restTemplate.getMessageConverters();
for (HttpMessageConverter<?> converter : converters) {
if (converter instanceof MappingJackson2HttpMessageConverter) {
MappingJackson2HttpMessageConverter jsonConverter =
(MappingJackson2HttpMessageConverter) converter;
jsonConverter.setObjectMapper(new ObjectMapper());
jsonConverter.setSupportedMediaTypes(
ImmutableList.of(
new MediaType(
"application", "json", MappingJackson2HttpMessageConverter.DEFAULT_CHARSET),
new MediaType(
"text", "javascript", MappingJackson2HttpMessageConverter.DEFAULT_CHARSET)));
}
}
return restTemplate;
}
@Bean
public LocalSessionFactoryBean createLocalSessionFactory(
@Qualifier("mainDataSource") DataSource dataSource) {
LocalSessionFactoryBean factory = new LocalSessionFactoryBean();
factory.setDataSource(dataSource);
factory.setPackagesToScan(
new String[] {
"com.abc.def..entities",
"com.abc.entities"
});
factory.setHibernateProperties(hibernateVCommitProperties());
return factory;
}
@Bean
public LocalSessionFactoryBean createToolSessionFactory(
@Qualifier("toolsDataSource") DataSource dataSource) {
LocalSessionFactoryBean factory = new LocalSessionFactoryBean();
factory.setDataSource(dataSource);
factory.setPackagesToScan(
new String[] {
"com.abc.def..entities",
"com.abc.entities"
});
factory.setHibernateProperties(hibernateVCommitProperties());
return factory;
}
@Scheduled(cron = "${server.cron}")
public void SyncJobTrigger() throws Exception {
if (log.isInfoEnabled()) {
}
JobParameters param =
new JobParametersBuilder()
.addString("JobID", String.valueOf(System.currentTimeMillis()))
.toJobParameters();
JobExecution execution = jobLauncher.run(populateServerDataJob(), param);
if (log.isInfoEnabled()) {
log.info("BATCH tools Server job finished with status: " + execution.getStatus());
}
}
//--------------------------------- JOBS ----------------------------------------------
@Bean
public Job populateServerDataJob() throws Exception {
return jobBuilderFactory
.get("populateData")
.start(serverRequestData()) // this step's writer is failing
.next(a)
.build();
}
@Bean
@StepScope
public HibernateCursorItemReader<Request> mylRequestReader() throws Exception {
// returns reader and works fine as seen in logs, data is fetched
}
@Bean
@StepScope
public requestToServerProcessor requestToServerRequestProcessor() {
return new requestToServerProcessor(mainDataSource);
}
// WRITER
@Bean
@StepScope
public HibernateItemWriter<ServerRequestDetails> serverRequestWriter() {
HibernateItemWriter<ServerRequestDetails> writer = new HibernateItemWriter();
writer.setSessionFactory(createLocalSessionFactory(mainDataSource).getObject());
return writer;
}
@Bean
@JobScope
public Step serverRequestData() throws Exception {
return stepBuilderFactory
.get("getServerRequestData")
.<Request, ServerRequestDetails>chunk(100)
.reader(mylRequestReader())
.processor(requestToServerRequestProcessor())
.writer(serverRequestWriter())
.build();
}
}
DataSourceConfiguration.class
@Configuration
public class DataSourceConfiguration {
private static final Logger log = LoggerFactory.getLogger(DataSourceConfiguration.class);
@Value("${spring.datasource.usern}")
private String insightsDbUser;
@Value("${spring.datasource.pass}")
private String insightsDbPass;
@Value("${spring.datasource.url}")
private String insightsDbConnection;
@Value("${tools.datasource.user}")
private String toolsDbUser
@Value("${tools.datasource.pass}")
private String toolsDbPass;
@Value("${tools.datasource.url}")
private String toolsDbConnection;
@Bean(name = "mainDataSource")
@Primary
public DataSource mainDataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl(insightsDbConnection);
dataSource.setUsername(insightsDbUser);
dataSource.setPassword(insightsDbPass);
if (log.isInfoEnabled()) {
//
}
return dataSource;
}
@Bean(name = "toolsDataSource")
public DataSource vtoolsDataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl(toolsDbConnection);
dataSource.setUsername(toolsDbUser);
dataSource.setPassword(toolsDbPass);
if (log.isInfoEnabled()) {
//
}
return dataSource;
}
}
这适用于 1.5,但在 Spring Boot 的 2.3.5 升级中出现以下异常:
javax.persistence.TransactionRequiredException: no transaction is in progress
at org.hibernate.internal.AbstractSharedSessionContract.checkTransactionNeededForUpdateOperation(AbstractSharedSessionContract.java:413)
at org.hibernate.internal.SessionImpl.checkTransactionNeededForUpdateOperation(SessionImpl.java:3397)
at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1354)
at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1349)
at org.springframework.batch.item.database.HibernateItemWriter.write(HibernateItemWriter.java:95)
at org.springframework.batch.item.database.HibernateItemWriter$$FastClassBySpringCGLIB$$1177da25.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:771)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)
at org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:136)
at org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:124)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:691)
at org.springframework.batch.item.database.HibernateItemWriter$$EnhancerBySpringCGLIB$$c0ff7bb9.write(<generated>)
at org.springframework.batch.core.step.item.SimpleChunkProcessor.writeItems(SimpleChunkProcessor.java:193)
at org.springframework.batch.core.step.item.SimpleChunkProcessor.doWrite(SimpleChunkProcessor.java:159)
at org.springframework.batch.core.step.item.SimpleChunkProcessor.write(SimpleChunkProcessor.java:294)
at org.springframework.batch.core.step.item.SimpleChunkProcessor.process(SimpleChunkProcessor.java:217)
at org.springframework.batch.core.step.item.ChunkOrientedTasklet.execute(ChunkOrientedTasklet.java:77)
at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:407)
at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:331)
at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:140)
at org.springframework.batch.core.step.tasklet.TaskletStep$2.doInChunkContext(TaskletStep.java:273)
at org.springframework.batch.core.scope.context.StepContextRepeatCallback.doInIteration(StepContextRepeatCallback.java:82)
at org.springframework.batch.repeat.support.RepeatTemplate.getNextResult(RepeatTemplate.java:375)
at org.springframework.batch.repeat.support.RepeatTemplate.executeInternal(RepeatTemplate.java:215)
at org.springframework.batch.repeat.support.RepeatTemplate.iterate(RepeatTemplate.java:145)
at org.springframework.batch.core.step.tasklet.TaskletStep.doExecute(TaskletStep.java:258)
at org.springframework.batch.core.step.AbstractStep.execute(AbstractStep.java:208)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:136)
at org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:124)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
at com.sun.proxy.$Proxy118.execute(Unknown Source)
at org.springframework.batch.core.job.SimpleStepHandler.handleStep(SimpleStepHandler.java:148)
at org.springframework.batch.core.job.AbstractJob.handleStep(AbstractJob.java:410)
at org.springframework.batch.core.job.SimpleJob.doExecute(SimpleJob.java:136)
at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:319)
at org.springframework.batch.core.launch.support.SimpleJobLauncher$1.run(SimpleJobLauncher.java:147)
at org.springframework.core.task.SyncTaskExecutor.execute(SyncTaskExecutor.java:50)
at org.springframework.batch.core.launch.support.SimpleJobLauncher.run(SimpleJobLauncher.java:140)
at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.execute(JobLauncherApplicationRunner.java:199)
at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.executeLocalJobs(JobLauncherApplicationRunner.java:173)
at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.launchJobFromProperties(JobLauncherApplicationRunner.java:160)
at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.run(JobLauncherApplicationRunner.java:155)
at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.run(JobLauncherApplicationRunner.java:150)
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:786)
at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:776)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:322)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1237)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49)
at org.springframework.boot.loader.Launcher.launch(Launcher.java:107)
at org.springframework.boot.loader.Launcher.launch(Launcher.java:58)
at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:88)
我在 StackOverflow 上搜索了一些类似的东西,但没有任何帮助。
我在属性文件中做了以下更改
spring.main.allow-bean-definition-overriding=true
因为我在某处得到了一些“无法创建 Bean,存在同名的 bean 错误”。
当项目构建时,我确实看到以下行:
2021-04-07 06:43:31.409 WARN 79404 --- [main] o.s.b.c.c.a.DefaultBatchConfigurer : No transaction manager was provided, using a DataSourceTransactionManager
解决方案
推荐阅读
- java - 反序列化具有一个元素的列表,如果列表大小为 1,则直接作为元素本身(Json 格式)
- excel - 将所有值从一张表复制并粘贴到另一张表
- git - 如何修复在非主分支上提交的修改子模块引用?
- apache-spark - 为什么 SparkContext 会创建大量与 Hive Metastore 的连接并扫描所有数据库?
- python - 如何:在 Windows 上为 Mac OS 创建 Python 应用程序
- python - 我无法在 Windows 上为 anaconda jupyter notebook 安装 pandas-datareader
- python - 当列名中有 `.` 时,Pandas 查询或评估
- php - 如何显示今天之前的日期,但我的查询是所有日期> = CURDATE(),来自同一列
- cesium - 信息框为空
- caching - 相同的查询按顺序执行,相同的执行时间?