JpaItemWriter in Spring batch: no transaction is in progress - java

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.

None of the classes you shared is annotated with #EnableBatchProcessing, so it is not clear which transaction manager is set on the StepBuilderFactory you use to create steps. The default transaction manager configured by #EnableBatchProcessing is a DataSourceTransactionManager, which knows nothing about the JPA context. Since you use JPA, so you need to configure a JpaTransactionManager in your step:
#JobScope
#Bean(name = WITHDRAW_MEMBERS_JOB + "_step")
public Step withdrawStep(JpaTransactionManager transactionManager) {
SimpleStepBuilder step = stepBuilderFactory.get("deleteExpiredMembersStep")
.<WithdrawMember, WithdrawMember>chunk(1000)
.transactionManager(transactionManager)
.reader(withdrawItemReader(null, null))
.processor(withdrawItemProcessor())
.writer(withdrawItemWriter());
return step.build();
}
If you use #EnableBatchProcessing, you need to provide a custom BatchConfigurer, something like:
#Bean
public BatchConfigurer batchConfigurer(DataSource dataSource, EntityManagerFactory entityManagerFactory) {
return new DefaultBatchConfigurer(dataSource) {
#Override
public PlatformTransactionManager getTransactionManager() {
return new JpaTransactionManager(entityManagerFactory);
}
};
}

Related

Failed to initialize the reader when testing a step scoped JdbcCursorItemReader

I get this error while testing my reader:
Failed to initialize the reader
org.springframework.batch.item.ItemStreamException: Failed to initialize the reader
at app//org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader.open(AbstractItemCountingItemStreamItemReader.java:153)
at app//org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader$$FastClassBySpringCGLIB$$ebb633d0.invoke(<generated>)
at app//org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
at app//org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:783)
at app//org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at app//org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:753)
at app//org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:137)
at app//org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:124)
at app//org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at app//org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:753)
at app//org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:698)
at app//org.springframework.batch.item.database.JdbcCursorItemReader$$EnhancerBySpringCGLIB$$403e222f.open(<generated>)
at app//com.europcar.tokenization.step.reader.BankCardReaderTest.lambda$readAll$0(BankCardReaderTest.java:131)
at app//org.springframework.batch.test.StepScopeTestUtils.doInStepScope(StepScopeTestUtils.java:38)
at app//com.europcar.tokenization.step.reader.BankCardReaderTest.readAll(BankCardReaderTest.java:127)
at app//com.europcar.tokenization.step.reader.BankCardReaderTest.readTest(BankCardReaderTest.java:120)
at java.base#17.0.3.1/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base#17.0.3.1/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base#17.0.3.1/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base#17.0.3.1/java.lang.reflect.Method.invoke(Method.java:568)
at app//org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:725)
at app//org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
at app//org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
at app//org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149)
at app//org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140)
at app//org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84)
at app//org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
at app//org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
at app//org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
at app//org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
at app//org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
at app//org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
at app//org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
at app//org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
at app//org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:214)
at app//org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at app//org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:210)
at app//org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:135)
at app//org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:66)
at app//org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151)
at app//org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at app//org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
at app//org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
at app//org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
at app//org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at app//org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
at app//org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
at java.base#17.0.3.1/java.util.ArrayList.forEach(ArrayList.java:1511)
at app//org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
at app//org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
at app//org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at app//org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
at app//org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
at app//org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
at app//org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at app//org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
at app//org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
at java.base#17.0.3.1/java.util.ArrayList.forEach(ArrayList.java:1511)
at app//org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
at app//org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
at app//org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at app//org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
at app//org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
at app//org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
at app//org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at app//org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
at app//org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
at app//org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35)
at app//org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
at app//org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:108)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:96)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:75)
at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.processAllTestClasses(JUnitPlatformTestClassProcessor.java:99)
at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.access$000(JUnitPlatformTestClassProcessor.java:79)
at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor.stop(JUnitPlatformTestClassProcessor.java:75)
at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.stop(SuiteTestClassProcessor.java:61)
at java.base#17.0.3.1/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base#17.0.3.1/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base#17.0.3.1/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base#17.0.3.1/java.lang.reflect.Method.invoke(Method.java:568)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94)
at jdk.proxy1/jdk.proxy1.$Proxy2.stop(Unknown Source)
at org.gradle.api.internal.tasks.testing.worker.TestWorker$3.run(TestWorker.java:193)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.executeAndMaintainThreadName(TestWorker.java:129)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:100)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:60)
at org.gradle.process.internal.worker.child.ActionExecutionWorker.execute(ActionExecutionWorker.java:56)
at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:133)
at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:71)
at app//worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69)
at app//worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74)
Caused by: org.springframework.jdbc.BadSqlGrammarException: Executing query; bad SQL grammar [select field1,field2
field3,
field4,
field5
from MYDB.MYTABLE wct]; nested exception is org.h2.jdbc.JdbcSQLSyntaxErrorException: Table "MYTABLE"
Table "MYTABLE" not found;
how can I avoid this error? when I debug I go throw the ReaderConfig
class and initiliaze reader when context is created, but when come to the test reader is not initialized!
some one can help me?
this is my test class,this is my test config for Reader and job Config.
I set an H2 database withs properties file above
#ActiveProfiles("test") #RunWith(SpringRunner.class) #PropertySource(ignoreResourceNotFound = true, value = "classpath:application-test.properties") #SpringBootTest #EnableAutoConfiguration #ContextConfiguration(classes = { MyFunctionJobConfiguration.class, ReaderConfig.class}) #TestExecutionListeners({ DependencyInjectionTestExecutionListener.class, DirtiesContextTestExecutionListener.class }) #DirtiesContext(classMode
= ClassMode.AFTER_CLASS) public class `MyEntity`ReaderTest {
#Autowired private JdbcCursorItemReader<MyEntity> MyEntityReader;
#Autowired private DataSource dataSource;
StepExecution stepExecution;
private static final Logger LOGGER = LoggerFactory.getLogger("TEST_LOGGER");
private JobParameters defaultJobParameters() {
JobParameters params = new JobParametersBuilder()
.addString("JobID", String.valueOf(System.currentTimeMillis()))
.toJobParameters();
return params; } #BeforeEach public void setUp() throws Exception { } public StepExecution getStepExecution() {
StepExecution stepExecution = MetaDataInstanceFactory.createStepExecution(defaultJobParameters());
return stepExecution; } #Test #Transactional void readTest() throws Exception {
List<MyEntity> MyEntities = readAll();
LOGGER.info("result of read : bank card ={}", MyEntities);
assertNotNull(MyEntities); }
private List<MyEntity> readAll() throws Exception {
// build step execution context
return StepScopeTestUtils.doInStepScope(
getStepExecution(),
() -> {
// init reader
MyEntityReader.open(stepExecution.getExecutionContext());
List<MyEntity> items = new ArrayList<>();
MyEntity MyEntity1;
while ((MyEntity1 = MyEntityReader.read()) != null) {
items.add(MyEntity1);
}
MyEntityReader.close();
return items;
}); } }
#Profile("test")
#Configuration
public class ReaderConfig {
#Autowired
private DataSource dataSource;
private MyEntityRowMapper MyEntityRowMapper = new MyEntityRowMapper();
private static final String SQL_FILE = "extract_entities_test.sql";
Integer maxCardsNumber;
public static final String MODULO_LABEL = ":modulo";
public static final String GRID_SIZE_LABEL = ":gridSize";
#Bean
#Primary
#StepScope
public JdbcCursorItemReader<MyEntity> MyEntityReader() throws IOException {
return initMyEntityReader(1,1);
}
#SqlGroup
({
#Sql(scripts={"classpath:create-tables.sql"}),
#Sql(scripts={"classpath:init_MyEntity_data.sql"})
})
public JdbcCursorItemReader<MyEntity> initMyEntityReader(int modulo, int gridSize) throws IOException {
JdbcCursorItemReader<MyEntity> cursorItemReader = new JdbcCursorItemReader<>();
ClassPathResource resource = new ClassPathResource(SQL_FILE);
BufferedReader reader = new BufferedReader(new InputStreamReader(resource.getInputStream()));
String query = FileCopyUtils.copyToString(reader);
query = query.replace(MODULO_LABEL, String.valueOf(modulo));
query = query.replace(GRID_SIZE_LABEL, String.valueOf(gridSize));
cursorItemReader.setSql(query);
final int partitionSize = 10 / gridSize;
cursorItemReader.setMaxItemCount(partitionSize);
cursorItemReader.setDataSource(dataSource);
cursorItemReader.setRowMapper(MyEntityRowMapper);
return cursorItemReader;
}
}
#Configuration
#EnableBatchProcessing
#RefreshScope
public class MyFunctionJobConfiguration {
#Autowired
public JobBuilderFactory jobBuilderFactory;
#Autowired
public StepBuilderFactory stepBuilderFactory;
#Autowired
JdbcCursorItemReader<MyEntity> reader;
#Value("${max-number-card-to-process}")
private Integer MAX_NUMBER_CARD;
#Value("${chunck-size:10}")
private int chunckSize;
#Value("${grid-size:1}")
private int gridSize;
private final static String JOB_DISABLED = "job is disabled, check the configuration file !";
#Value("${job.enabled}")
private boolean batchIsEnabled;
private static final Logger LOGGER = LoggerFactory.getLogger("FUNCTIONAL_LOGGER");
#Bean
#StepScope
#RefreshScope
public MyEntityWriter writer() {
return new MyEntityWriter();
}
#Bean
#StepScope
#RefreshScope
public MyFunctionProcessor processor() throws IOException {
return new MyFunctionProcessor();
}
#Bean
public MyPrationner partitioner() {
return new MyPrationner();
}
#Bean
public Step masterStep() throws SQLException, IOException, ClassNotFoundException {
return stepBuilderFactory.get("masterStep")
.partitioner("MyFunctionStep", partitioner())
.step(MyFunctionStep())
.gridSize(gridSize)
.taskExecutor(MyFunctionTaskExecutor())
.build();
}
#Bean
public TaskExecutor myFunctionTaskExecutor() {
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
taskExecutor.setThreadNamePrefix("MyFunctionTaskExecutor_");
int corePoolSize = gridSize + 2;
int maxPoolSize = corePoolSize * 2;
taskExecutor.setMaxPoolSize(maxPoolSize);
taskExecutor.setAllowCoreThreadTimeOut(true);
taskExecutor.setCorePoolSize(corePoolSize);
taskExecutor.setQueueCapacity(Integer.MAX_VALUE);
return taskExecutor;
}
#Bean
public Step myFunctionStep() throws IOException, ClassNotFoundException, SQLException {
return stepBuilderFactory.get("MyFunctionStep")
.<MyEntity, MyEntity>chunk(chunckSize)
.reader(reader)
.faultTolerant()
.skipLimit(MAX_NUMBER_CARD)
.skip(InvalidCardNumberException.class)
.skip(TokenManagementException.class)
.processor(processor())
.listener(new MyEntityProcessListener())
.writer(writer())
.listener(new MyEntityWriteListener())
.build();
}
#Bean
public Job myFunctionJob(#Qualifier("MyFunctionStep") Step myFunctionStep)
throws SQLException, IOException, ClassNotFoundException {
if (!batchIsEnabled) {
LOGGER.error(JOB_DISABLED);
System.exit(0);
}
return jobBuilderFactory.get("MyFunctionJob")
.listener(new MyFunctionJobListener())
.incrementer(new RunIdIncrementer())
.flow(masterStep())
.end()
.build();
}
}
logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE
spring.datasource.type=com.zaxxer.hikari.HikariDataSource
spring.datasource.pool-name=${spring.application.name}-pool
spring.datasource.url=jdbc:h2:mem:MYDB;DB_CLOSE_DELAY=-1;INIT=CREATE SCHEMA IF NOT EXISTS MYDB
spring.datasource.username=sa
spring.datasource.password=sa
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.database-platform=org.hibernate.dialect.H2Dialect
spring.jpa.defer-datasource-initialization=true
#initialize batch schema
spring.batch.jdbc.initialize-schema=always
spring.datasource.initialization-mode=always
spring.sql.init.mode=always
spring.jpa.hibernate.ddl-auto=none
#spring.jpa.hibernate.ddl-auto=create
spring.h2.console.enabled=true
# Custom H2 Console URL
spring.h2.console.path=/h2
spring.jpa.generate-ddl=true
#jpa.hibernate.ddl-auto=create-drop
spring.datasource.hikari.pool-name=${spring.application.name}-pool
spring.datasource.hikari.connection-timeout=20000
spring.datasource.hikari.maximum-pool-size=30
spring.datasource.hikari.max-lifetime=86400000
spring.datasource.hikari.idle-timeout=600000
spring.datasource.hikari.keepalive-time=30000
spring.datasource.hikari.minimum-idle=10
spring.datasource.jmx-enabled=true`
I put creation tables and injection data sql scripts in ReaderConfig with #Sql anotation when I define the reader Bean for test.
It is too late to create tables at that point. You need to initialize the data source with Spring Batch tables and your custom tables before running your job. This can be done on the test setup phase, not the item reader setup phase.
Please check the documentation on how to initialize the data source with Spring Boot.

How can I use java configuration of spring batch without spring boot?

I'm new to spring batch and I'm trying to learn about it.
I implemented datasource and batch configuration but it doesn't seem to work, because
Exception in thread "main" org.springframework.jdbc.BadSqlGrammarException: PreparedStatementCallback; bad SQL grammar [SELECT JOB_INSTANCE_ID, JOB_NAME from BATCH_JOB_INSTANCE where JOB_NAME = ? and JOB_KEY = ?]; nested exception is java.sql.SQLSyntaxErrorException: Table '$tableName.batch_job_instance' doesn't exist
DataSourceConfiguration class :
#Configuration
public class DataSourceConfiguration {
#Bean
public DataSource mysqlDataSource() throws SQLException {
final SimpleDriverDataSource dataSource = new SimpleDriverDataSource();
dataSource.setDriver(new com.mysql.cj.jdbc.Driver());
dataSource.setUrl("jdbc:mysql://localhost:3306/task4");
dataSource.setUsername("name");
dataSource.setPassword("password");
return dataSource;
}
}
And I have Batch configuration class, but I dont know #EnableBatchProcessing annotation works without springboot
#Configuration
#EnableBatchProcessing
#Import(DataSourceConfiguration.class)
public class BatchConfiguration {
#Autowired
private JobBuilderFactory jobs;
#Autowired
private StepBuilderFactory steps;
#Autowired
private DataSource dataSource;
#Bean
public ItemReader<User> itemReader() {
return new JdbcCursorItemReaderBuilder<User>()
.dataSource(this.dataSource)
.name("creditReader")
.sql("select userLogin, userEmail, userPassword, accountBalance from userInfo")
.rowMapper(new UserRowMapper())
.build();
}
#Bean
public ItemWriter<User> simpleItemWriter(){
return new SimpleUserWriter();
}
#Bean
public Job sampleJob() {
return this.jobs.get("sampleJob")
.start(step1())
.build();
}
#Bean
public Step step1() {
return this.steps.get("step1")
.<User,User>chunk(10)
.reader(itemReader())
.writer(simpleItemWriter())
.build();
}
}
Main class contains those lines of code :
public class Demo {
public static void main(String[] args) throws SQLException {
ApplicationContext context = new AnnotationConfigApplicationContext(BatchConfiguration.class);
context.getBean("jobRepository");
JobLauncher jobLauncher = context.getBean("jobLauncher",JobLauncher.class);
Job job = context.getBean("sampleJob", Job.class);
try {
JobExecution execution = jobLauncher.run(job, new JobParameters());
System.out.println("Job Exit Status : "+ execution.getStatus());
} catch (JobExecutionException e) {
System.out.println("Job ExamResult failed");
e.printStackTrace();
}
}
}
How can I solve this problem?Thanks for helping
The error seems to say that you are missing the tables needed by Spring batch.
Check https://docs.spring.io/spring-batch/docs/4.3.x/reference/html/schema-appendix.html
You can also find SQL files ready for the different DB engine under org/springframework/bacth/core/schema-<DB>.sql in the spring batch core jar file

JPA with Spring Embebed Database not records found

Starting from a program that was connected to a mysql database, using spring, JPA and JDBC, I am trying to configure that application to use the H2 database in embedded mode.
With MYSQL everything works fine, but with H2 not.
I can not get H2 to return any records, although the records are there so if I do the same query through JDBC, if I see them.
The configuration that I have is the following:
#Configuration
#EnableJpaRepositories("yages.yagesserver")
#EnableTransactionManagement
public class JpaConfig {
#Bean
public DataSource dataSource() {
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
EmbeddedDatabase db = builder
.setType(EmbeddedDatabaseType.H2)
.setName("yagesh2")
.ignoreFailedDrops(true)
.addScript("db/sql/create-db.sql")
.addScript("db/sql/insert-data.sql")
.generateUniqueName(false)
.build();
return db;
}
#Bean
public HibernateExceptionTranslator hibernateExceptionTranslator() {
return new HibernateExceptionTranslator();
}
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource) throws NamingException {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(dataSource());
em.setPackagesToScan(new String[]{"yages.yagesserver", "yages.yagesserver.dao"});
em.setPersistenceUnitName("yages-server");
em.setJpaVendorAdapter(jpaVendorAdapter());
em.afterPropertiesSet();
return em;
}
#Bean
public JpaVendorAdapter jpaVendorAdapter() {
HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
jpaVendorAdapter.setGenerateDdl(false);
jpaVendorAdapter.setDatabase(Database.H2);
jpaVendorAdapter.setShowSql(true);
return jpaVendorAdapter;
}
#Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory emf) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(emf);
return transactionManager;
}
}
So if I write this code:
String s="SELECT cal_ano,cal_mes,cal_fecini,cal_fecfin from calendario where cal_ano=? and cal_mes = ?";
List<Calendario> cal =
jdbc.query(s, new Object[] { ano,mes},
(rs, rowNum) -> new Calendario(
rs.getInt("cal_ano"),rs.getInt("cal_mes"),rs.getDate("cal_fecini"),rs.getDate("cal_fecfin"))
);
System.out.println("getDatosSemana. Size "+cal.size()+ "Fecha Inicio: "+cal.get(0).getFechaInicio());
Optional<Calendario> calOpc = calendarioRepositorio.getCalendario(new CalendarioKey(ano - 1, mes));
System.out.println("getDatosSemana. Optional is present: "+calOpc.isPresent());
When I use JDBC I see that in the calendar table if the record exists, but when using JPA, it does not seem to find anything.
This is the output in my console:
getDatosSemana. Size 1Fecha Inicio: 2018-01-28
Hibernate: select calendario0_.cal_ano as cal_ano1_0_0_, calendario0_.cal_mes as cal_mes2_0_0_, calendario0_.cal_fecfin as cal_fecf3_0_0_, calendario0_.cal_fecini as cal_feci4_0_0_ from calendario calendario0_ where calendario0_.cal_ano=? and calendario0_.cal_mes=?
getDatosSemana. Optional is present: false
Of course I have the DAO classes and my repository that extends from a CrudRepository.
Any suggestions, please?
I'm sorry. I have found the error.
It was a failure foolishness. I called the JPA function with the parameters of year and month reversed.
Sometimes you do not see the obvious.

liquibase exception DSRA9350E: Operation Connection.rollback is not allowed during a global transaction

I have a spring application deplyoed in WebSphere container.
I trying to initialize data using liquibase.
This is my DataSource configuration:
#Bean
public JndiTemplate jndi() {
return new JndiTemplate();
}
#Bean
public PlatformTransactionManager transactionManager() {
return new WebSphereUowTransactionManager();
}
#Bean(name = "primary")
public AbstractEntityManagerFactoryBean entityManagerFactory() {
final LocalContainerEntityManagerFactoryBean entityManagerFactory = new LocalContainerEntityManagerFactoryBean();
entityManagerFactory.setPersistenceUnitName(PERSTESTENCE_UNIT_NAME);
HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
jpaVendorAdapter.setGenerateDdl(true);
jpaVendorAdapter.setDatabase(Database.H2);
entityManagerFactory.setJpaVendorAdapter(jpaVendorAdapter);
return entityManagerFactory;
}
#Bean
public DataSource dataSource() throws NamingException {
return jndi().lookup(DATA_SOURCE_ADDRESS, DataSource.class);
}
And this is the code that runs database initialisation:
#Startup
#Singleton
#Interceptors(SpringBeanAutowiringInterceptor.class)
public class Startup {
#Autowired
private DbInit dbInit;
#PostConstruct
public void initialize() {
try {
dbInit.doMigrations(null);
} catch (SQLException | LiquibaseException e) {
LOG.error(e);
}
}
I get an exception on application startup:
Caused by: liquibase.exception.DatabaseException: liquibase.exception.DatabaseException: java.sql.SQLException: DSRA9350E: Operation Connection.rollback is not allowed during a global transaction.
at liquibase.database.AbstractJdbcDatabase.rollback(AbstractJdbcDatabase.java:1143)
at liquibase.lockservice.StandardLockService.acquireLock(StandardLockService.java:197)
... 142 more
Caused by: liquibase.exception.DatabaseException: java.sql.SQLException: DSRA9350E: Operation Connection.rollback is not allowed during a global transaction.
at liquibase.database.jvm.JdbcConnection.rollback(JdbcConnection.java:340)
at liquibase.database.AbstractJdbcDatabase.rollback(AbstractJdbcDatabase.java:1141)
... 143 more
Caused by: java.sql.SQLException: DSRA9350E: Operation Connection.rollback is not allowed during a global transactionи.
at com.ibm.ws.rsadapter.jdbc.WSJdbcConnection.rollback(WSJdbcConnection.java:3372)
at liquibase.database.jvm.JdbcConnection.rollback(JdbcConnection.java:337)
... 144 more
I know that I can't use rollback() in container-managed transaction but I don't know, how to configure this for liquibase.
I've tried to set Non-transactional data source property in WS DataSource configuration but it didn't help.
How can I solve this problem?

DataSource must not be null

My application doesnt use persistence.xml. So I tried using LocalContainerEntityManagerFactoryBean to create a custom EntityManager. But I get error as DataSource must not be null. Can anyone help on this issue?
PersistenceJPAConfig.java
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories
public class PersistenceJPAConfig {
#Autowired
private DataSource dataSource;
#Autowired
JpaVendorAdapter jpaVendorAdapter;
#Bean(name = "personEntityManager")
public EntityManager entityManager() {
return entityManagerFactory().createEntityManager();
}
#Bean(name = "personEntityManagerFactory")
public EntityManagerFactory entityManagerFactory() {
LocalContainerEntityManagerFactoryBean lef = new LocalContainerEntityManagerFactoryBean();
lef.setDataSource(dataSource);
lef.setJpaVendorAdapter(jpaVendorAdapter);
lef.setPackagesToScan("com.myc.cc.domain.Person");
lef.setPersistenceUnitName("personPersistenceUnit");
lef.afterPropertiesSet();
return lef.getObject();
}
#Primary
#Bean(name = "personTransactionManager")
public PlatformTransactionManager transactionManager() {
return new JpaTransactionManager(entityManagerFactory());
}
}
SearchPersonPredicates.java
public static Predicate findIdByEM(final Long pId) {
PersistenceJPAConfig jpaConfig = new PersistenceJPAConfig();
EntityManager manager= jpaConfig.entityManager();
QPerson qPerson = QPerson.person;
QAddress qAddress = QAddress.address;
BooleanBuilder booleanBuilder = new BooleanBuilder();
JPAQuery jpaQuery = new JPAQuery(manager);
JPASubQuery subQuery = new JPASubQuery();
Predicate predicate;
if (pId != null) {
booleanBuilder.or(QAddress.person_no.eq(pId));
}
predicate = booleanBuilder.getValue();
jpaQuery = jpaQuery.from(qAddress).join(qPerson).on(predicate);
subQuery.from(qPerson, qAddress);
return predicate;
}
SearchPersonServiceImpl.java
public List<Person> findPnumberbyEM(Long id) {
Iterable<Person> person = personRepository.findAll(findIdByEM(id));
return constructList(person);
}
private List<Person> constructList(Iterable<Person> persons) {
List<Person> list = new ArrayList<Person>();
for (Person person : persons) {
list.add(person);
}
}
Error
17:52:35.337 ERROR 7016 --- [nio-8080-exec-2] o.a.c.c.C.[.[.[.[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [/cc_dev] threw exception [Request processing failed; nested exception is java.lang.IllegalArgumentException: DataSource must not be null] with root cause
java.lang.IllegalArgumentException: DataSource must not be null
at org.springframework.util.Assert.notNull(Assert.java:112)
at org.springframework.jdbc.datasource.lookup.SingleDataSourceLookup.<init>(SingleDataSourceLookup.java:40)
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.setDataSource(LocalContainerEntityManagerFactoryBean.java:238)
at com.myc.cc.repository.PersistenceJPAConfig.entityManagerFactory(PersistenceJPAConfig.java:43)
at com.myc.cc.repository.PersistenceJPAConfig.entityManager(PersistenceJPAConfig.java:37)
at com.myc.cc.repository.SearchPersonPredicates.findIdByEM(SearchPersonPredicates.java:121)
at com.myc.cc.service.impl.SearchPersonServiceImpl.findPnumberbyEM(SearchPersonServiceImpl.java:70)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:201)
at com.sun.proxy.$Proxy114.findPnumberbyEM(Unknown Source)
at com.myc.cc.web.SearchPersonController.searchPerson(SearchPersonController.java:109)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
Thanks in advance
Your datasource property may not be getting initialized. Try adding #Value to datasource property:
#Autowired
#Value("${property.reference}")
private DataSource dataSource;

Categories