Spring Batch - 如何防止 batch 在 DB 中存储事务
Spring Batch - How to prevent batch from storing transactions in DB
先说问题:
我在我的 DEV 环境中使用 Spring-Batch 很好。当我将代码移至生产环境时,我 运行 遇到了问题。在我的 DEV 环境中,Spring-Batch 能够毫无问题地在我们的 DB2 数据库服务器中创建它的事务数据表。当我们转到 PROD 时,这不是一个选项,因为这是一个只读作业。
尝试的解决方案:
搜索 Stack Overflow 我找到了这个帖子:
Spring-Batch without persisting metadata to database?
听起来很完美,所以我添加了
@Bean
public ResourcelessTransactionManager transactionManager() {
return new ResourcelessTransactionManager();
}
@Bean
public JobRepository jobRepository(ResourcelessTransactionManager transactionManager) throws Exception {
MapJobRepositoryFactoryBean mapJobRepositoryFactoryBean = new MapJobRepositoryFactoryBean(transactionManager);
mapJobRepositoryFactoryBean.setTransactionManager(transactionManager);
return mapJobRepositoryFactoryBean.getObject();
}
我还通过调用 .reporitory(jobRepository) 将其添加到我的工作中。
但是我明白了
Caused by: java.lang.NullPointerException: null
at org.springframework.batch.core.repository.dao.MapJobExecutionDao.synchronizeStatus(MapJobExecutionDao.java:158) ~[spring-batch-core-3.0.6.RELEASE.jar:3.0.6.RELEASE]
所以我不确定在这里做什么。我是 Spring 的新手,所以我边走边自学。我对其他解决方案持开放态度,例如内存数据库,但我也无法让它们工作。我不需要在运行之间保存任何状态或会话信息,但是我 运行 的数据库查询将 return 大约一百万行左右,所以我需要分块获取。
如有任何建议或帮助,我们将不胜感激。
这并没有直接回答你的问题,但这不是一个好的解决方案;基于地图的存储库应该仅用于测试。它会在内存中无限增长。
我建议你使用像sqlite这样的嵌入式数据库。将单独的数据库用于作业元数据的主要问题是您应该协调您使用的两个数据库之间的事务(以便元数据的状态与数据的状态相匹配),但由于看起来您甚至没有写在主数据库中,这对您来说可能不是问题。
您可以很容易地使用内存数据库(例如 H2 或 HSQL)。您可以在此处找到示例:http://www.mkyong.com/spring/spring-embedded-database-examples/.
至于 Map-backed 作业存储库,它确实提供了 method 来清除其内容:
public void clear()
Convenience method to clear all the map DAOs globally, removing all entities.
请注意,基于 Map 的作业存储库不适合在分区步骤和其他多线程中使用。
以下似乎已经帮我完成了工作:
@Bean
public DataSource dataSource() {
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
EmbeddedDatabase db = builder
.setType(EmbeddedDatabaseType.HSQL)
.build();
return db;
}
现在 Spring 不会在我们的生产数据库中创建表,并且当 JVM 退出时状态会丢失,因此似乎没有任何东西悬而未决。
更新: 上面的代码给我们造成了并发错误。我们通过放弃 EmbeddedDatabaseBuilder 并以这种方式声明 HSQLDB 来解决这个问题:
@Bean
public BasicDataSource dataSource() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName("org.hsqldb.jdbcDriver");
dataSource.setUrl("jdbc:hsqldb:mem:testdb;sql.enforce_strict_size=true;hsqldb.tx=mvcc");
dataSource.setUsername("sa");
dataSource.setPassword("");
return dataSource;
}
主要区别是我们可以在连接字符串中指定 mvcc(多版本并发控制)来解决问题。
将这个 bean 添加到 AppClass
@Bean
public PlatformTransactionManager transactionManager() {
return new ResourcelessTransactionManager();
}
@Bean
public JobExplorer jobExplorer() throws Exception {
MapJobExplorerFactoryBean jobExplorerFactory = new MapJobExplorerFactoryBean(mapJobRepositoryFactoryBean());
jobExplorerFactory.afterPropertiesSet();
return jobExplorerFactory.getObject();
}
@Bean
public MapJobRepositoryFactoryBean mapJobRepositoryFactoryBean() {
MapJobRepositoryFactoryBean mapJobRepositoryFactoryBean = new MapJobRepositoryFactoryBean();
mapJobRepositoryFactoryBean.setTransactionManager(transactionManager());
return mapJobRepositoryFactoryBean;
}
@Bean
public JobRepository jobRepository() throws Exception {
return mapJobRepositoryFactoryBean().getObject();
}
@Bean
public JobLauncher jobLauncher() throws Exception {
SimpleJobLauncher simpleJobLauncher = new SimpleJobLauncher();
simpleJobLauncher.setJobRepository(jobRepository());
return simpleJobLauncher;
}
先说问题: 我在我的 DEV 环境中使用 Spring-Batch 很好。当我将代码移至生产环境时,我 运行 遇到了问题。在我的 DEV 环境中,Spring-Batch 能够毫无问题地在我们的 DB2 数据库服务器中创建它的事务数据表。当我们转到 PROD 时,这不是一个选项,因为这是一个只读作业。
尝试的解决方案:
搜索 Stack Overflow 我找到了这个帖子: Spring-Batch without persisting metadata to database?
听起来很完美,所以我添加了
@Bean
public ResourcelessTransactionManager transactionManager() {
return new ResourcelessTransactionManager();
}
@Bean
public JobRepository jobRepository(ResourcelessTransactionManager transactionManager) throws Exception {
MapJobRepositoryFactoryBean mapJobRepositoryFactoryBean = new MapJobRepositoryFactoryBean(transactionManager);
mapJobRepositoryFactoryBean.setTransactionManager(transactionManager);
return mapJobRepositoryFactoryBean.getObject();
}
我还通过调用 .reporitory(jobRepository) 将其添加到我的工作中。
但是我明白了
Caused by: java.lang.NullPointerException: null
at org.springframework.batch.core.repository.dao.MapJobExecutionDao.synchronizeStatus(MapJobExecutionDao.java:158) ~[spring-batch-core-3.0.6.RELEASE.jar:3.0.6.RELEASE]
所以我不确定在这里做什么。我是 Spring 的新手,所以我边走边自学。我对其他解决方案持开放态度,例如内存数据库,但我也无法让它们工作。我不需要在运行之间保存任何状态或会话信息,但是我 运行 的数据库查询将 return 大约一百万行左右,所以我需要分块获取。
如有任何建议或帮助,我们将不胜感激。
这并没有直接回答你的问题,但这不是一个好的解决方案;基于地图的存储库应该仅用于测试。它会在内存中无限增长。
我建议你使用像sqlite这样的嵌入式数据库。将单独的数据库用于作业元数据的主要问题是您应该协调您使用的两个数据库之间的事务(以便元数据的状态与数据的状态相匹配),但由于看起来您甚至没有写在主数据库中,这对您来说可能不是问题。
您可以很容易地使用内存数据库(例如 H2 或 HSQL)。您可以在此处找到示例:http://www.mkyong.com/spring/spring-embedded-database-examples/.
至于 Map-backed 作业存储库,它确实提供了 method 来清除其内容:
public void clear()
Convenience method to clear all the map DAOs globally, removing all entities.
请注意,基于 Map 的作业存储库不适合在分区步骤和其他多线程中使用。
以下似乎已经帮我完成了工作:
@Bean
public DataSource dataSource() {
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
EmbeddedDatabase db = builder
.setType(EmbeddedDatabaseType.HSQL)
.build();
return db;
}
现在 Spring 不会在我们的生产数据库中创建表,并且当 JVM 退出时状态会丢失,因此似乎没有任何东西悬而未决。
更新: 上面的代码给我们造成了并发错误。我们通过放弃 EmbeddedDatabaseBuilder 并以这种方式声明 HSQLDB 来解决这个问题:
@Bean
public BasicDataSource dataSource() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName("org.hsqldb.jdbcDriver");
dataSource.setUrl("jdbc:hsqldb:mem:testdb;sql.enforce_strict_size=true;hsqldb.tx=mvcc");
dataSource.setUsername("sa");
dataSource.setPassword("");
return dataSource;
}
主要区别是我们可以在连接字符串中指定 mvcc(多版本并发控制)来解决问题。
将这个 bean 添加到 AppClass
@Bean
public PlatformTransactionManager transactionManager() {
return new ResourcelessTransactionManager();
}
@Bean
public JobExplorer jobExplorer() throws Exception {
MapJobExplorerFactoryBean jobExplorerFactory = new MapJobExplorerFactoryBean(mapJobRepositoryFactoryBean());
jobExplorerFactory.afterPropertiesSet();
return jobExplorerFactory.getObject();
}
@Bean
public MapJobRepositoryFactoryBean mapJobRepositoryFactoryBean() {
MapJobRepositoryFactoryBean mapJobRepositoryFactoryBean = new MapJobRepositoryFactoryBean();
mapJobRepositoryFactoryBean.setTransactionManager(transactionManager());
return mapJobRepositoryFactoryBean;
}
@Bean
public JobRepository jobRepository() throws Exception {
return mapJobRepositoryFactoryBean().getObject();
}
@Bean
public JobLauncher jobLauncher() throws Exception {
SimpleJobLauncher simpleJobLauncher = new SimpleJobLauncher();
simpleJobLauncher.setJobRepository(jobRepository());
return simpleJobLauncher;
}