Spring Batch "Nome oggetto non valido BATCH_JOB_INSTANCE"

Sep 27 2020

Ho creato un batch primaverile per interrogare un database del server SQL di Azure e scrivere i dati in un file CSV. Non ho le createautorizzazioni per il database. Ottengo questo errore Invalid Object name BATCH_JOB_INSTANCEdurante l'esecuzione del batch. Non voglio che le tabelle dei metadati del batch primaverile vengano create nel database principale. Oppure sarebbe utile se posso averli in un altro db locale o in memoria come h2db. Ho anche spring-batch-initialize-schema=nevergià aggiunto , che era il caso con la maggior parte delle risposte a domande simili qui, ma ciò non ha aiutato.

Modificare:

Ho risolto l' Invalid Object nameerrore impedendo la creazione delle tabelle di metadati nel database principale estendendo la DefaultBatchConfigurerclasse e sovrascrivendo il setDataSourcemetodo, facendole così creare nel repository di mappe in memoria. Ora voglio provare due opzioni:

  1. Come creare le tabelle dei metadati in un database locale o in memoria come h2db.
  2. Oppure, se ho le tabelle dei metadati già create nel database principale, in uno schema diverso dalla tabella principale da cui sto recuperando. Come indirizzare il mio lavoro a quelle tabelle di metadati in un altro schema, per memorizzare i dati del lavoro e dei dettagli del passaggio in essi.
@Configuration
public class SpringBatchConfig extends DefaultBatchConfigurer{

@Override
    public void setDataSource(DataSource datasource) {

    }
...

Il mio file application.properties ha questo aspetto:

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

Risposte

MahmoudBenHassine Oct 02 2020 at 07:57

Come creare le tabelle dei metadati in un database locale o in memoria come h2db.

Puoi usare spring.batch.initialize-schema=embeddedper quello.

Oppure, se ho le tabelle dei metadati già create nel database principale, in uno schema diverso dalla tabella principale da cui sto recuperando. Come indirizzare il mio lavoro a quelle tabelle di metadati in un altro schema, per memorizzare i dati del lavoro e dei dettagli del passaggio in essi.

Spring batch funziona su un'origine dati, non su uno schema particolare. Se le tabelle dei metadati si trovano in uno schema diverso, è necessario creare una seconda origine dati che punta a quello schema e impostarla sul repository del lavoro.

JosephXu Oct 09 2020 at 06:45

Ho creato una demo con due origini dati. I metadati batch verranno visualizzati in H2 DB e l'origine dati del lavoro è Azure SQL.

Ecco la struttura del progetto:

  1. È necessario definire una DataSourceConfigclasse e utilizzare l' @Primaryannotazione per il bean DataSource:
@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. Nella classe ItemReaderDbDemo, usiamo @Autowired @Qualifier("mssqlDataSource")per specificare dataSource nell'attività Spring Batch:
@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. Ecco la mia 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. Restituisce il risultato atteso dal mio Azure SQL. A proposito, il mio nome utente Azure sql non dispone delle autorizzazioni di creazione per il database.
    Il risultato mostra: