![](/img/trans.png)
[英]@Autowired and UnsatisfiedDependencyException in Spring integration test
[英]How to use autowired repositories in Spring Batch integration test?
在為 Spring 批處理作業編寫集成測試時,我遇到了一些問題。 主要問題是,只要在批處理作業中啟動事務,就會引發異常。
嗯,第一件事。 想象一下這是一個簡單工作的步驟。 為簡單起見的Tasklet
。 當然,它用於適當的批處理配置 ( MyBatchConfig
),為簡潔起見,我也將其省略。
@Component
public class SimpleTask implements Tasklet {
private final MyRepository myRepository;
public SimpleTask(MyRepository myRepository) {
this.myRepository = myRepository;
}
@Override
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
myRepository.deleteAll(); // or maybe saveAll() or some other @Transactional method
return RepeatStatus.FINISHED;
}
}
MyRepository
是一個非常不特殊的CrudRepository
。
現在,為了測試該作業,我使用以下測試 class。
@SpringBatchTest
@EnableAutoConfiguration
@SpringJUnitConfig(classes = {
H2DataSourceConfig.class, // <-- this is a configuration bean for an in-memory testing database
MyBatchConfig.class
})
public class MyBatchJobTest {
@Autowired
private JobLauncherTestUtils jobLauncherTestUtils;
@Autowired
private JobRepositoryTestUtils jobRepositoryTestUtils;
@Autowired
private MyRepository myRepository;
@Test
public void testJob() throws Exception {
var testItems = List.of(
new MyTestItem(1),
new MyTestItem(2),
new MyTestItem(3)
);
myRepository.saveAll(testItems); // <--- works perfectly well
jobLauncherTestUtils.launchJob();
}
}
當涉及到 tasklet 執行,更准確地說是deleteAll()
方法調用時,會觸發此異常:
org.springframework.transaction.CannotCreateTransactionException: Could not open JPA EntityManager for transaction; nested exception is java.lang.IllegalStateException: Already value [org.springframework.jdbc.datasource.ConnectionHolder@68f48807] for key [org.springframework.jdbc.datasource.DriverManagerDataSource@49a6f486] bound to thread [SimpleAsyncTaskExecutor-1]
at org.springframework.orm.jpa.JpaTransactionManager.doBegin(JpaTransactionManager.java:448)
...
你知道為什么會這樣嗎?
作為一種解決方法,我目前使用ArrayList
模擬存儲庫並使用@MockBean
支持它,但我猜這不是發明者的意圖。
有什么建議嗎?
親切的問候
更新 1.1(包括解決方案)
提到的數據源配置class是
@Configuration
@EnableJpaRepositories(
basePackages = {"my.project.persistence.repository"},
entityManagerFactoryRef = "myTestEntityManagerFactory",
transactionManagerRef = "myTestTransactionManager"
)
@EnableTransactionManagement
public class H2DataSourceConfig {
@Bean
public DataSource myTestDataSource() {
var dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("org.h2.Driver");
dataSource.setUrl("jdbc:h2:mem:myDb;DB_CLOSE_DELAY=-1");
return dataSource;
}
@Bean
public LocalContainerEntityManagerFactoryBean myTestEntityManagerFactory() {
var emFactory = new LocalContainerEntityManagerFactoryBean();
var adapter = new HibernateJpaVendorAdapter();
adapter.setDatabasePlatform("org.hibernate.dialect.H2Dialect");
adapter.setGenerateDdl(true);
emFactory.setDataSource(myTestDataSource());
emFactory.setPackagesToScan("my.project.persistence.model");
emFactory.setJpaVendorAdapter(adapter);
return emFactory;
}
@Bean
public PlatformTransactionManager myTestTransactionManager() {
return new JpaTransactionManager(myTestEntityManagerFactory().getObject());
}
@Bean
public BatchConfigurer testBatchConfigurer() {
return new DefaultBatchConfigurer() {
@Override
public PlatformTransactionManager getTransactionManager() {
return myTestTransactionManager();
}
};
}
}
默認情況下,當您在應用程序上下文中聲明數據源時,Spring Batch 將使用DataSourceTransactionManager
來驅動步驟事務,但此事務管理器對您的 JPA 上下文一無所知。
如果要使用另一個事務管理器,則需要覆蓋BatchConfigurer#getTransactionManager
並返回要用於驅動步驟事務的事務管理器。 在您的情況下,您只是在應用程序上下文中聲明一個事務管理器 bean,這還不夠。 這里有一個簡單的例子:
@Bean
public BatchConfigurer batchConfigurer() {
return new DefaultBatchConfigurer() {
@Override
public PlatformTransactionManager getTransactionManager() {
return new JpaTransactionManager(myTestEntityManagerFactory().getObject());
}
};
}
有關詳細信息,請參閱參考文檔。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.