Spring Batch - 模块化批处理范围规则

时间:2014-08-15 19:02:35

标签: hibernate spring-batch

我有一个玩具项目,它将人名和怪物名称列入数据库,然后使用然后将怪物的姓氏更改为Monster。要使用HibernateItemWriter

将项目写入数据库

3个作业中的每一个都有自己的配置文件,它们捆绑在一个配置中,并带有@EnableBatchProcessing(modular = true)注释。

这一切都有效。

但是,当单个作业的配置文件中存在@EnableBatchProcessing时,HibernateItemWriter无法再找到hibernate会话。

有人可以解释实现这一目标的应用程序上下文范围规则吗?

在不单独使用它们时,在单个作业配置上使用@EnableBatchProcessing是相当不错的。它允许在弹簧自动配置完成工作时导入和运行它们。

申请

@Import({ImportAllConfiguration.class, EmbededDatasourceConfiguration.class, HibernateConfiguration.class})
@Configuration
public class Application {


    public static void main(String[] args) throws SQLException, BeansException, JobExecutionAlreadyRunningException, JobRestartException, JobInstanceAlreadyCompleteException, NoSuchJobException, JobParametersInvalidException {
        ApplicationContext ctx = SpringApplication.run(Application.class, args);

        JobRegistry jobRegistry = ctx.getBean(JobRegistry.class);
        Job job1 = jobRegistry.getJob("importMonsterJob");

        JobLauncher launcher = ctx.getBean(JobLauncher.class);
        launcher.run(job1, new JobParameters());

    }

}

ImportAllConfiguration

@Configuration
@EnableBatchProcessing(modular=true)
public class ImportAllConfiguration {
    @Bean
    public ApplicationContextFactory someJobs() {
        return new GenericApplicationContextFactory(ImportMonsterConfiguration.class);
    }

    @Bean
    public ApplicationContextFactory someMoreJobs() {
        return new GenericApplicationContextFactory(ImportPersonConfiguration.class);
    }

    @Bean
    public ApplicationContextFactory evenMoreJobs() {
        return new GenericApplicationContextFactory(MatchMonsterToPersonConfiguration.class);
    }
}

Hibernate配置

@Configuration
public class HibernateConfiguration {

    @Autowired
    private DataSource dataSource;

    @Bean
    public HibernateTransactionManager transactionManager(
            SessionFactory sessionFactory) {
        HibernateTransactionManager txManager = new HibernateTransactionManager();
        txManager.setSessionFactory(sessionFactory);

        return txManager;
    }

    @Bean
    public JdbcTemplate jdbcTemplate() {
        JdbcTemplate jdbcTemplate = new JdbcTemplate();
        jdbcTemplate.setDataSource(dataSource);
        return jdbcTemplate;
    }

    @SuppressWarnings("serial")
    public Properties hibernateProperties() {
        return new Properties() {
            {
                //setProperty(Environment.CURRENT_SESSION_CONTEXT_CLASS, "thread");
                setProperty(Environment.HBM2DDL_AUTO, "create");
                setProperty(Environment.SHOW_SQL, "true");
            }
        };
    }

    @Bean
    public LocalSessionFactoryBean sessionFactory() {
        LocalSessionFactoryBean annotationSessionFactoryBean = new LocalSessionFactoryBean();
        annotationSessionFactoryBean.setPackagesToScan("hello.model");

        annotationSessionFactoryBean.setDataSource(dataSource);
        annotationSessionFactoryBean
                .setHibernateProperties(hibernateProperties());
        return annotationSessionFactoryBean;
    }

}

作业配置文件。在这里添加@EnableBatchProcessing将导致HibernateItemWriter无法找到会话。

@Configuration
@EnableBatchProcessing <-- This causes the exception
public class ImportMonsterConfiguration  {

    @Autowired
    protected SessionFactory sessionFactory;

    @Autowired
    protected StepBuilderFactory stepBuilderFactory;

    @Autowired
    protected JobBuilderFactory jobBuilderFactory;

    @Bean
    public <T> ItemWriter<T> writer() {
        return new HibernateItemWriter<T>() {
            {
                setSessionFactory(sessionFactory);
            }
        };
    }

    @Bean
    public ItemReader<Monster> reader() {
        FlatFileItemReader<Monster> reader = new FlatFileItemReader<Monster>();
        reader.setResource(new ClassPathResource("sample-data.csv"));
        reader.setLineMapper(new DefaultLineMapper<Monster>() {
            {
                setLineTokenizer(new DelimitedLineTokenizer() {
                    {
                        setNames(new String[] { "firstName", "lastName" });
                    }
                });
                setFieldSetMapper(new BeanWrapperFieldSetMapper<Monster>() {
                    {
                        setTargetType(Monster.class);
                    }
                });
            }
        });
        return reader;
    }

    @Bean
    public ItemProcessor<Monster, Monster> processor() {
        return new MonsterItemProcessor();
    }

    @Bean
    public Job importMonsterJob() {
        return jobBuilderFactory.get("importMonsterJob")
                .incrementer(new RunIdIncrementer()).flow(step2()).end()
                .build();
    }

    @Bean
    public LocalValidatorFactoryBean validator() {
        LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
        return validator;
    }

    @Bean
    public ItemProcessor<Monster, Monster> validatingProcessor() {
        SpringValidator<Monster> springValidator = new SpringValidator<Monster>();
        springValidator.setValidator(validator());

        ValidatingItemProcessor<Monster> validatingItemProcessor = new ValidatingItemProcessor<Monster>();
        validatingItemProcessor.setValidator(springValidator);

        return validatingItemProcessor;
    }

    @Bean
    public Step step2() {
        return stepBuilderFactory.get("step2").<Monster, Monster> chunk(10)
                .reader(reader()).processor(processor())
                .processor(validatingProcessor()).writer(writer()).build();
    }

}

抛出异常。

org.hibernate.HibernateException: No Session found for current thread
    at org.springframework.orm.hibernate4.SpringSessionContext.currentSession(SpringSessionContext.java:106)
    at org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:1014)
    at org.springframework.batch.item.database.HibernateItemWriter.doWrite(HibernateItemWriter.java:134)
    at org.springframework.batch.item.database.HibernateItemWriter.write(HibernateItemWriter.java:113)

1 个答案:

答案 0 :(得分:2)

您提供自己的交易管理器。要覆盖Spring Batch随@EnableBatchProcessing提供的那些,您需要提供自己的BatchConfigurer实现。否则,我们将为您添加一个,在这种情况下,它不会成为基于Hibernate的事务管理器。 HibernateConfiguration扩展DefaultBatchConfigurer并使用您的事务管理器代码覆盖getTransactionManager方法。