Spring Batch “Ungültiger Objektname BATCH_JOB_INSTANCE”

Sep 27 2020

Ich habe einen Spring Batch erstellt, um eine Azure SQL Server-Datenbank abzufragen und die Daten in eine CSV-Datei zu schreiben. Ich habe keine createBerechtigungen für die Datenbank. Ich erhalte diesen Fehler Invalid Object name BATCH_JOB_INSTANCEbeim Ausführen des Stapels. Ich möchte nicht, dass die Spring-Batch-Metadatentabellen in der Hauptdatenbank erstellt werden. Oder es wäre hilfreich, wenn ich sie in einer anderen lokalen oder speicherinternen Datenbank wie h2db haben könnte. Ich habe auch spring-batch-initialize-schema=neverbereits hinzugefügt , was bei den meisten Antworten auf ähnliche Fragen hier der Fall war, aber das hat nicht geholfen.

Bearbeiten:

Ich habe den Invalid Object nameFehler behoben , indem verhindert wurde, dass die Metadatentabellen in der Hauptdatenbank erstellt werden, indem die DefaultBatchConfigurerKlasse erweitert und die setDataSourceMethode überschrieben wurde , sodass sie im speicherinternen Map-Repository erstellt wurden. Jetzt möchte ich zwei Optionen ausprobieren:

  1. So erstellen Sie die Metadatentabellen in einer lokalen Datenbank oder einer speicherinternen Datenbank wie h2db.
  2. Oder Wenn ich die Metadatentabellen bereits in der Hauptdatenbank erstellt habe, in einem anderen Schema als meiner Haupttabelle, aus der ich abrufe. Wie ich meinen Job auf diese Metadatentabellen in einem anderen Schema verweise, um die Job- und Schrittdetaildaten in diesen zu speichern.
@Configuration
public class SpringBatchConfig extends DefaultBatchConfigurer{

@Override
    public void setDataSource(DataSource datasource) {

    }
...

Meine Datei application.properties sieht folgendermaßen aus:

spring.datasource.url=
spring.datasource.username=
spring.datasource.password=
spring.datasource.driver-class-name=com.microsoft.sqlserver.jdbc.SQLServerDriver

spring-batch-initialize-schema=never
spring.batch.job.enabled=false

spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.SQLServer2012Dialect

Antworten

MahmoudBenHassine Oct 02 2020 at 07:57

So erstellen Sie die Metadatentabellen in einer lokalen Datenbank oder einer speicherinternen Datenbank wie h2db.

Sie können dafür verwenden spring.batch.initialize-schema=embedded.

Oder Wenn ich die Metadatentabellen bereits in der Hauptdatenbank erstellt habe, in einem anderen Schema als meiner Haupttabelle, aus der ich abrufe. Wie ich meinen Job auf diese Metadatentabellen in einem anderen Schema verweise, um die Job- und Schrittdetaildaten in diesen zu speichern.

Spring Batch arbeitet mit einer Datenquelle, nicht mit einem bestimmten Schema. Wenn sich Metadatentabellen in einem anderen Schema befinden, müssen Sie eine zweite Datenquelle erstellen, die auf dieses Schema verweist, und diese im Job-Repository festlegen.

JosephXu Oct 09 2020 at 06:45

Ich habe eine Demo mit zwei Datenquellen erstellt. Stapelmetadaten werden in H2 DB gespeichert, und die Jobdatenquelle ist Azure SQL.

Hier ist die Projektstruktur:

  1. Wir müssen eine DataSourceConfigKlasse definieren und @PrimaryAnnotation für DataSource Bean verwenden:
@Configuration
public class DataSourceConfig {

    @Bean(name = "mssqlDataSource")
    @ConfigurationProperties(prefix = "spring.datasource")
    public DataSource appDataSource(){
        return DataSourceBuilder.create().build();
    }
    
    @Bean(name = "h2DataSource")
    @Primary
    // @ConfigurationProperties(prefix="spring.datasource.h2")
    public DataSource h2DataSource() {
        return DataSourceBuilder.create()
                .url("jdbc:h2:mem:thing:H2;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE")
                .driverClassName("org.h2.Driver")
                .username("sa")
                .password("")                   
                .build();
    }
    
}
  1. In der ItemReaderDbDemo-Klasse geben wir @Autowired @Qualifier("mssqlDataSource")die dataSource in der Spring Batch-Task an:
@Configuration
public class ItemReaderDbDemo {
    
    //generate task Object
    @Autowired
    private JobBuilderFactory jobBuilderFactory;
    
    //Step exec tasks
    //generate step Object
    @Autowired
    private StepBuilderFactory stepBuilderFactory;

    @Autowired
    @Qualifier("mssqlDataSource")
    private DataSource dataSource;

    @Autowired
    @Qualifier("dbJdbcWriter")
    private ItemWriter<? super Todo> dbJdbcWriter;
    
    @Bean
    public Job itemReaderDbDemoJob() {
        return jobBuilderFactory.get("itemReaderDbDemoJob").start(itemReaderDbStep()).build();
    }

    @Bean
    public Step itemReaderDbStep() {
        return stepBuilderFactory.get("itemReaderDbStep")
                .<Todo,Todo>chunk(2)
                .reader(dbJdbcReader())
                .writer(dbJdbcWriter)
                .build();
    }

    @Bean
    @StepScope
    public JdbcPagingItemReader<Todo> dbJdbcReader() {
        JdbcPagingItemReader<Todo> reader = new JdbcPagingItemReader<Todo>();
        reader.setDataSource(dataSource);
        reader.setFetchSize(2);
        reader.setRowMapper(new  RowMapper<Todo>() {
            @Override
            public Todo mapRow(ResultSet rs, int rowNum) throws SQLException {
                Todo todo = new Todo();
                todo.setId(rs.getLong(1));
                todo.setDescription(rs.getString(2));
                todo.setDetails(rs.getString(3));
                return todo;
            }   
            
        });
        SqlServerPagingQueryProvider provider = new  SqlServerPagingQueryProvider();
        provider.setSelectClause("id,description,details");
        provider.setFromClause("from dbo.todo");
        
        //sort
        Map<String,Order> sort = new HashMap<>(1);
        sort.put("id", Order.DESCENDING);
        provider.setSortKeys(sort);
        
        reader.setQueryProvider(provider);
        return reader;
    }
}

  1. Hier ist meine application.properties:
logging.level.org.springframework.jdbc.core=DEBUG

spring.datasource.driverClassName=com.microsoft.sqlserver.jdbc.SQLServerDriver
spring.datasource.jdbcUrl=jdbc:sqlserver://josephserver2.database.windows.net:1433;database=<Your-Database-Name>;encrypt=true;trustServerCertificate=false;hostNameInCertificate=*.database.windows.net;loginTimeout=30;
spring.datasource.username=<Your-UserName>
spring.datasource.password=<Your-Password>
spring.datasource.initialization-mode=always
  1. Es gibt das erwartete Ergebnis von meinem Azure SQL zurück. Mein Azure SQL-Benutzername verfügt übrigens nicht über Erstellungsberechtigungen für die Datenbank.
    Das Ergebnis zeigt: