Spring Batch “Nome de objeto inválido BATCH_JOB_INSTANCE”
Criei um lote de primavera para consultar um banco de dados do servidor SQL do Azure e gravar os dados em um arquivo CSV. Não tenho createpermissão para o banco de dados. Recebo este erro Invalid Object name BATCH_JOB_INSTANCEao executar o lote. Não quero que as tabelas de metadados de lote do Spring sejam criadas no banco de dados principal. Ou seria útil se eu pudesse tê-los em outro banco de dados local ou na memória como o h2db. Também spring-batch-initialize-schema=neverjá adicionei , que era o caso da maioria das respostas a perguntas semelhantes aqui, mas isso não ajudou.
Editar:
Resolvi o Invalid Object nameerro evitando que as tabelas de metadados fossem criadas no banco de dados principal estendendo a DefaultBatchConfigurerclasse e substituindo o setDataSourcemétodo, fazendo com que fossem criadas no repositório de mapas na memória. Agora, quero tentar duas opções:
- Como fazer com que as tabelas de metadados sejam criadas em um banco de dados local ou em memória como o h2db.
- Ou Se eu já tiver as tabelas de metadados criadas no banco de dados principal, em um esquema diferente do da minha tabela principal que estou buscando. Como apontar meu trabalho para essas tabelas de metadados em outro esquema, para armazenar os dados de detalhes do trabalho e da etapa neles.
@Configuration
public class SpringBatchConfig extends DefaultBatchConfigurer{
@Override
public void setDataSource(DataSource datasource) {
}
...
Meu arquivo application.properties tem a seguinte aparência:
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
Respostas
Como fazer com que as tabelas de metadados sejam criadas em um banco de dados local ou em memória como o h2db.
Você pode usar spring.batch.initialize-schema=embeddedpara isso.
Ou Se eu já tiver as tabelas de metadados criadas no banco de dados principal, em um esquema diferente do da minha tabela principal que estou buscando. Como apontar meu trabalho para essas tabelas de metadados em outro esquema, para armazenar os dados de detalhes do trabalho e da etapa neles.
spring batch funciona em uma fonte de dados, não em um esquema específico. Se as tabelas de metadados estiverem em um esquema diferente, você precisará criar uma segunda fonte de dados apontando para esse esquema e configurá-lo no repositório de tarefas.
Eu criei uma demonstração com duas fontes de dados. Os metadados em lote serão armazenados no banco de dados H2 e a fonte de dados do trabalho é o Azure SQL.
Aqui está a estrutura do projeto:
- Precisamos definir uma
DataSourceConfigclasse e usar@Primaryanotações para o 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();
}
}
- Na classe ItemReaderDbDemo, usamos
@Autowired @Qualifier("mssqlDataSource")para especificar o dataSource na tarefa 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;
}
}
- Aqui está meu 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
- Ele retorna o resultado esperado do meu Azure SQL. A propósito, meu nome de usuário SQL do Azure não tem permissões de criação para o banco de dados.
O resultado mostra: