如何配置spring批处理不自动创建用于存储元数据的批处理表?

Posted

技术标签:

【中文标题】如何配置spring批处理不自动创建用于存储元数据的批处理表?【英文标题】:How to configure spring batch not to auto create batch tables for storing meta data? 【发布时间】:2019-07-23 20:03:38 【问题描述】:

我正在开发一个使用 JPA 对 PostGres 数据库执行 CRUD 操作的 spring 批处理。我正在使用 Spring Boot 2.1.3。即使我添加了以下配置以禁用 Spring 批处理以使用我的 postgres 数据库存储批处理作业元数据信息,我得到“错误:关系“batch_job_instance”不存在”异常,如下所示。我也遵循了here 中提到的解决方案。谁能建议需要做哪些额外的事情?

hibernate.temp.use_jdbc_metadata_defaults=false
spring.batch.initialize-schema=never
spring.batch.initializer.enabled=false

例外:

 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 org.postgresql.util.PSQLException: ERROR: relation "batch_job_instance" does not exist
  Position: 39
    at org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.doTranslate(SQLErrorCodeSQLExceptionTranslator.java:234)
    at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:72)
    at org.springframework.jdbc.core.JdbcTemplate.translateException(JdbcTemplate.java:1444)
    at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:632)
    at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:669)
    at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:700)
    at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:712)
    at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:768)
    at org.springframework.batch.core.repository.dao.JdbcJobInstanceDao.getJobInstance(JdbcJobInstanceDao.java:148)
    at org.springframework.batch.core.repository.support.SimpleJobRepository.getLastJobExecution(SimpleJobRepository.java:297)
    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.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:294)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
    at com.sun.proxy.$Proxy69.getLastJobExecution(Unknown Source)
    at org.springframework.batch.core.launch.support.SimpleJobLauncher.run(SimpleJobLauncher.java:101)
    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.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
    at org.springframework.batch.core.configuration.annotation.SimpleBatchConfiguration$PassthruAdvice.invoke(SimpleBatchConfiguration.java:127)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
    at com.sun.proxy.$Proxy78.run(Unknown Source)
    at com.test.BatchApplication.main(BatchApplication.java:28)
Caused by: org.postgresql.util.PSQLException: ERROR: relation "batch_job_instance" does not exist
  Position: 39
    at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2440)
    at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:2183)
    at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:308)
    at org.postgresql.jdbc.PgStatement.executeInternal(PgStatement.java:441)
    at org.postgresql.jdbc.PgStatement.execute(PgStatement.java:365)
    at org.postgresql.jdbc.PgPreparedStatement.executeWithFlags(PgPreparedStatement.java:143)
    at org.postgresql.jdbc.PgPreparedStatement.executeQuery(PgPreparedStatement.java:106)
    at com.zaxxer.hikari.pool.ProxyPreparedStatement.executeQuery(ProxyPreparedStatement.java:52)
    at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.executeQuery(HikariProxyPreparedStatement.java)
    at org.springframework.jdbc.core.JdbcTemplate$1.doInPreparedStatement(JdbcTemplate.java:678)
    at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:617)
    ... 31 more

【问题讨论】:

【参考方案1】:

由于您告诉 Spring Boot不要创建元数据表,因此您需要在数据源中预先手动创建它们。对于 Postgres,您需要在运行作业之前在数据库上执行 schema-postgresql.sql 脚本

编辑:如果您不想保留元数据表,可以使用内存中基于 Map 的作业存储库:

@Configuration
@EnableBatchProcessing
public class MyJobConfiguration extends DefaultBatchConfigurer 

    @Override
    protected JobRepository createJobRepository() throws Exception 
        MapJobRepositoryFactoryBean factoryBean = new MapJobRepositoryFactoryBean();
        factoryBean.afterPropertiesSet();
        return factoryBean.getObject();
    

    // other beans related to job definition

请注意,基于地图的作业存储库不适用于生产用途。

另一种选择是使用基于 JDBC 的作业存储库,但使用嵌入式数据库,如 HSQLDB、H2 等。

希望这会有所帮助。

【讨论】:

我根本不希望我的批处理作业实例创建元数据表。您能否建议我们是否可以通过任何配置更改来实现这一目标? 我在答案中添加了一个示例。希望对您有所帮助。 @MahmoudBenHassine - 虽然我的 pom.xml 文件中没有 H2 依赖项,但它仍然有效。你能解释一下这是如何工作的吗? 地图作业存储库不使用内存数据库(它使用地图存储元数据),这就是即使您的类路径中没有 h2 也可以工作的原因。我的回答中的第二个选项是使用基于 jdbc 的作业存储库,它需要一个数据库(无论是否是内存数据库)。希望这能澄清你的困惑。 @MahmoudBenHassine - 谢谢第一部分对我来说很干净。第二个选项部分仍然不清楚。请您再次澄清一下好吗?了解它是如何工作的很重要!任何链接也会有所帮助

以上是关于如何配置spring批处理不自动创建用于存储元数据的批处理表?的主要内容,如果未能解决你的问题,请参考以下文章

Spring Batch 不使用自定义数据源创建表

如何在 Spring Security SAML 示例中配置 IDP 元数据和 SP 元数据?

Spring Batch -元数据模式

Spring Boot 配置元数据

spring怎么配置EHCACHE

为系统文件创建和使用Mercurial存储库