我在Spring Boot应用程序中使用Spring Batch,如下所示。 Spring Batch和该应用程序似乎可以在该配置下正常工作。
但是,使用简单的Dao-Test的配置(不适用于Spring Batch),我得到以下异常。没有Spring Batch配置,测试运行良好。 更新:如果我配置为将自己的JobRepository与事务管理器一起使用(在类MyBatchConfigurer中),则会出现问题。
我试图为Spring Batch提供另一个事务管理器,但是我正在从一个异常到另一个异常。
org.springframework.dao.InvalidDataAccessApiUsageException: no transaction is in progress; nested exception is javax.persistence.TransactionRequiredException: no transaction is in progress
Caused by: javax.persistence.TransactionRequiredException: no transaction is in progress
at org.hibernate.internal.SessionImpl.checkTransactionNeeded(SessionImpl.java:3505)
at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1427)
at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1423)
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.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:350)
at com.sun.proxy.$Proxy165.flush(Unknown Source)
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.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:305)
at com.sun.proxy.$Proxy165.flush(Unknown Source)
at com.foo.dao.GenericDao.save(GenericDao.java:60)
at com.foo.dao.GenericDao$$FastClassBySpringCGLIB$$71a0996b.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:746)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139)
... 37 more
测试设置
@SpringBootTest
@RunWith(SpringRunner.class)
@EntityScan(basePackages = "com.foo.entity")
@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD)
@TestPropertySource("/mytest.properties")
@Sql(executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD, scripts = "classpath:/testdata.sql")
public class MyTest {
@Inject
private OrderDao sut;
@Test
public void test_findByAnotherFieldId() {
final Order order = // build an order ...
sut.save(order);
final Order result = sut.findByAnotherFieldId("valueOfOtherField");
assertThat(result).isEqualTo(order);
}
}
Spring Batch Job配置
@Configuration
@EnableBatchProcessing
@Import(OracleDatabaseConfig.class)
@ComponentScan(basePackageClasses = MyBatchConfigurer.class)
public class BatchJobConfig {
// Injects...
@Qualifier("analyseOrdersJob")
@Bean
public Job analyseOrdersJob() {
return jobBuilderFactory.get("analyseOrdersJob").start(analyseOrdersStep()).build();
}
@Bean
public Step analyseOrdersStep() {
return stepBuilderFactory.get("analyseOrdersStep").<Order, String>chunk(4)
.reader(orderItemReader) //
.processor(orderItemProcessor) //
.writer(orderItemWriter) //
.build();
}
}
Spring Batch配置
@Component
public class MyBatchConfigurer extends DefaultBatchConfigurer {
@Inject
private DataSource dataSource;
@Override
public JobRepository getJobRepository() {
try {
return extractJobRepository();
} catch (final Exception e) {
throw new BatchConfigurationException(e);
}
}
private JobRepository extractJobRepository() throws Exception {
final JobRepositoryFactoryBean factory = new JobRepositoryFactoryBean();
factory.setDataSource(dataSource);
factory.setTransactionManager(getTransactionManager());
factory.afterPropertiesSet();
return factory.getObject();
}
}
ItemReader
@Component
@StepScope
public class OrderItemReader implements ItemReader<Order> {
@Inject
private OrderDao orderdao;
private int nextOrderIndex;
private List<Order> orders;
@PostConstruct
public void postConstruct() {
orders = orderdao.findAll();
}
@Override
public Order read() {
if (nextOrderIndex < orders.size()) {
final Order order = orders.get(nextOrderIndex);
nextOrderIndex++;
return order;
}
return null;
}
}
ItemWriter和ItemProcessor的配置类似。