i'd like to use JpaItemWriter in conditions of multi-datasource in spring batch, JPA. below is my config (there are log, common, member db config)
- common db config
@Configuration
@EnableJpaRepositories(
basePackages = "com.member.batch.dao.common",
entityManagerFactoryRef = "commonEntityManager",
transactionManagerRef = "commonTransactionManager"
)
public class CommonConfiguration {
@ConfigurationProperties(prefix = "spring.datasource-common.hikari")
@Primary
@Bean(name = "commonDataSource")
public DataSource commonDataSource() {
return DataSourceBuilder.create().type(HikariDataSource.class).build();
}
@ConfigurationProperties("spring.jpa.common-properties")
@Bean(name = "commonHibernateProperties")
public HashMap<String, Object> hibernateProperties() {
return new HashMap<>();
}
@Bean
public LocalContainerEntityManagerFactoryBean commonEntityManager() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(commonDataSource());
em.setPackagesToScan("com.member.batch.entities.common");
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
final HashMap<String, Object> properties = hibernateProperties();
em.setJpaPropertyMap(properties);
return em;
}
@Bean(name = "commonTransactionManager")
public PlatformTransactionManager commonTransactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(commonEntityManager().getObject());
return transactionManager;
}
}
- log db config
@Configuration
@EnableJpaRepositories(
basePackages = "com.member.batch.dao.log",
entityManagerFactoryRef = "logEntityManager",
transactionManagerRef = "logTransactionManager"
)
public class LogConfiguration {
// same format with common
}
- member db config
@Configuration
@EnableJpaRepositories(
basePackages = "com.member.batch.dao.member",
entityManagerFactoryRef = "memberEntityManager",
transactionManagerRef = "memberTransactionManager"
)
public class MemberConfiguration {
// same format with common
}
and i have to use configures in my job
@Slf4j
@RequiredArgsConstructor
@Configuration
public class WithdrawMembersJobConfiguration {
public static final String WITHDRAW_MEMBERS_JOB = "withdrawMembersJob";
private final MessageSource messageSource;
private final JobBuilderFactory jobBuilderFactory;
private final StepBuilderFactory stepBuilderFactory;
private final CustomJobListener customJobListener;
private final ScheduleJobService scheduleJobService;
private final EntityManagerFactory entityManagerFactory;
@Bean
@Primary
public Job withdrawMembersJob() {
return jobBuilderFactory.get(WITHDRAW_MEMBERS_JOB)
.start(withdrawStep())
.listener(customJobListener)
.build();
}
@JobScope
@Bean(name = WITHDRAW_MEMBERS_JOB + "_step")
public Step withdrawStep() {
SimpleStepBuilder step = stepBuilderFactory.get("deleteExpiredMembersStep")
.<WithdrawMember, WithdrawMember>chunk(1000)
.reader(withdrawItemReader(null, null))
.processor(withdrawItemProcessor())
.writer(withdrawItemWriter());
return step.build();
}
@StepScope
@Bean(name = WITHDRAW_MEMBERS_JOB + "_reader")
public JpaPagingItemReader<WithdrawMember> withdrawItemReader(@org.springframework.beans.factory.annotation.Value("#{jobParameters[requestDate]}") String requestDate,
@org.springframework.beans.factory.annotation.Value("#{jobParameters[status]}") WithdrawStatus status) {
LocalDateTime scheduledDate = LocalDateTime.now().with(LocalTime.MAX);
log.info("scheduled date is " + scheduledDate);
if (status == null) {
status = WithdrawStatus.WSC001;
}
Map<String, Object> parameters = new HashMap<>();
parameters.put("scheduledDate", scheduledDate);
parameters.put("status", status);
return new JpaPagingItemReaderBuilder<WithdrawMember>()
.name("withdrawReader")
.parameterValues(parameters)
.entityManagerFactory(entityManagerFactory)
.queryString("select m from WithdrawMember m where m.scheduleDate < :scheduledDate and m.status = :status")
.pageSize(1000)
.build();
}
@StepScope
@Bean(name = WITHDRAW_MEMBERS_JOB + "_processor")
public ItemProcessor<WithdrawMember, WithdrawMember> withdrawItemProcessor() {
return new ItemProcessor<WithdrawMember, WithdrawMember>() {
@Override
public WithdrawMember process(WithdrawMember item) throws Exception {
log.info("withdraw info , " + item.getReason());
return item;
}
};
}
@StepScope
@Bean(name = WITHDRAW_MEMBERS_JOB + "_writer")
public JpaItemWriter withdrawItemWriter() {
return new JpaItemWriterBuilder<WithdrawMember>()
.entityManagerFactory(entityManagerFactory)
.build();
}
}
but now i am having getting error ,below is my console
2022-09-15 16:18:01.521 DEBUG 1552 --- [eduler_Worker-4] o.s.j.d.DataSourceTransactionManager : Creating new transaction with name [org.springframework.batch.core.repository.support.SimpleJobRepository.update]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
2022-09-15 16:18:01.521 DEBUG 1552 --- [eduler_Worker-4] o.s.j.d.DataSourceTransactionManager : Acquired Connection [HikariProxyConnection@238016139 wrapping com.mysql.cj.jdbc.ConnectionImpl@3023ef72] for JDBC transaction
2022-09-15 16:18:01.521 DEBUG 1552 --- [eduler_Worker-4] o.s.j.d.DataSourceTransactionManager : Switching JDBC Connection [HikariProxyConnection@238016139 wrapping com.mysql.cj.jdbc.ConnectionImpl@3023ef72] to manual commit
2022-09-15 16:18:01.541 DEBUG 1552 --- [eduler_Worker-4] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL query
2022-09-15 16:18:01.541 DEBUG 1552 --- [eduler_Worker-4] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL statement [SELECT VERSION FROM BATCH_JOB_EXECUTION WHERE JOB_EXECUTION_ID=?]
2022-09-15 16:18:01.577 DEBUG 1552 --- [eduler_Worker-4] o.s.b.c.r.dao.JdbcJobExecutionDao : Truncating long message before update of JobExecution: JobExecution: id=1956, version=1, startTime=Thu Sep 15 16:18:00 KST 2022, endTime=Thu Sep 15 16:18:01 KST 2022, lastUpdated=Thu Sep 15 16:18:01 KST 2022, status=FAILED, exitStatus=exitCode=FAILED;exitDescription=javax.persistence.TransactionRequiredException: no transaction is in progress
at org.hibernate.internal.AbstractSharedSessionContract.checkTransactionNeededForUpdateOperation(AbstractSharedSessionContract.java:422)
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)
javax.persistence.TransactionRequiredException: no transaction is in progress
at org.hibernate.internal.AbstractSharedSessionContract.checkTransactionNeededForUpdateOperation(AbstractSharedSessionContract.java:422) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.internal.SessionImpl.checkTransactionNeededForUpdateOperation(SessionImpl.java:3397) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1354) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1349) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:362) ~[spring-orm-5.3.9.jar:5.3.9]
at com.sun.proxy.$Proxy119.flush(Unknown Source) ~[na:na]
at org.springframework.batch.item.database.JpaItemWriter.write(JpaItemWriter.java:94) ~[spring-batch-infrastructure-4.3.3.jar:4.3.3]
at org.springframework.batch.item.database.JpaItemWriter$$FastClassBySpringCGLIB$$29c4242e.invoke(<generated>) ~[spring-batch-infrastructure-4.3.3.jar:4.3.3]
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.3.9.jar:5.3.9]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:779) ~[spring-aop-5.3.9.jar:5.3.9]
at
i don't know why i get this error. i could get result of itemReader.