Spring Batch无法打开JPA EntityManager进行交易;嵌套异常是java.lang.illegal



我的春季批处理作业每5分钟开始启动 - 基本上它读取一个字符串,使用字符串作为SQL查询中的参数,并打印出结果SQL结果列表。通常它似乎运行正常,但是我注意到每5-10次运行一次的日志中零星错误

2017-05-05 11:13:26.101  INFO 9572 --- [nio-8081-exec-8] c.u.r.s.AgentCollectorServiceImpl    : Could not open JPA E
ntityManager for transaction; nested exception is java.lang.IllegalStateException: Transaction already active

我的工作就像我的AgentCollectorserviceimpl类一样开始

@Override
public void addReportIds(List<Integer> reportIds) {
    try {
            .toJobParameters();
        jobLauncher.run(job, jobParameters);
    } catch (Exception e) {
        log.info(e.getMessage());
    }
}

我的batchconfig班级看起来像

@Configuration
@EnableBatchProcessing
@Import(AppConfig.class)
public class BatchConfig {
    @Autowired
    private JobBuilderFactory jobBuilderFactory;
    @Autowired
    private StepBuilderFactory stepBuilderFactory;
    @Autowired
    private AppConfig appConfig;
    @Bean
    public Reader reader() {
        return new Reader();
    }
    @Bean
    public Processor processor() {
        return new Processor();
    }
    @Bean
    public Writer writer() {
        return new Writer();
    }
    @Bean
    public Job job() {
        return jobBuilderFactory.get("job")
            .incrementer(new RunIdIncrementer())
            .flow(step1())
            .end()
            .build();
    }
    @Bean
    public Step step1() {
        return stepBuilderFactory.get("step1")
            .<String, String> chunk(1)
            .reader(reader())
            .processor(processor())
            .writer(writer())
            .build();
    }
}

我的AppConfig课程看起来像

@Configuration
@PropertySource("classpath:application.properties")
@ComponentScan
public class AppConfig {

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
        LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
        em.setDataSource(organizationDataSource());
        em.setPackagesToScan(new String[]{"com.organization.agentcollector.model"});
        JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        em.setJpaVendorAdapter(vendorAdapter);
        em.setJpaProperties(additionalProperties());
        return em;
    }
    Properties additionalProperties() {
        Properties properties = new Properties();
        properties.setProperty("hibernate.dialect", "com.organization.agentcollector.config.SQLServerDialectOverrider");
        return properties;
    }
    @Bean
    JpaTransactionManager transactionManager(final EntityManagerFactory emf) {
        JpaTransactionManager transactionManager = new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
        return transactionManager;
    }

我的处理器类看起来像

public class Processor implements ItemProcessor<String, String> {
    private final Logger log = LoggerFactory.getLogger(Processor.class);
    @Autowired
    EventReportsDAOImpl eventReportsDAOImpl;
    @Override
    public String process(String reportIdsJson) throws Exception {
        String eventReportsJson = eventReportsDAOImpl.listEventReportsInJsonRequest(reportIdsJson);
        //System.out.println(returnContent+"PROCESSOR");
        return eventReportsJson;
    }
}

我的daoimpl班级看起来像

@Component
@Transactional
public class EventReportsDAOImpl implements EventReportsDAO {
    @PersistenceContext
    private EntityManager em;
    @Override
    public EventReports getEventReports(Integer reportId) {
        return null;
    }
    @Override
    public String listEventReportsInJsonRequest(String reportIds) {
        System.out.println("Event Report reportIds processing");
        ArrayList<EventReports> erArr = new ArrayList<EventReports>();
        String reportIdsList = reportIds.substring(1, reportIds.length() - 1);
        //System.out.println(reportIdsList);
        try {
            StoredProcedureQuery q = em.createStoredProcedureQuery("sp_get_event_reports", "eventReportsResult");
            q.registerStoredProcedureParameter("reportIds", String.class, ParameterMode.IN);
            q.setParameter("reportIds", reportIdsList);
            boolean isResultSet = q.execute();  
            erArr = (ArrayList<EventReports>) q.getResultList();
        } catch (Exception e) {
            System.out.println("No event reports found for list " + reportIdsList);
        }
        return erArr.toString();
    }

我认为春季会自动管理交易。错误似乎表明交易没有正确关闭?

我尝试的一件事是从我的代码中删除所有 @transactional注释,因为我读到@enableBatchProcessing已经将交易管理器注入了每个步骤 - 但是当我这样做时,我看到了"交易已经有效"错误的频率更高。

关于如何解决此问题的任何建议,谢谢!

@Transactional符号建立了事务范围,该范围决定了交易何时开始和结束,也称为其边界。如果您在此边界外操作,您会收到错误。

首先,我发现春季交易中最有帮助的文档:http://docs.spring.io/spring-framework/docs/4.2.x/spring-framework-framework-reference-rpery/html/transaction.html特别是本节

其次,您可能希望启用跟踪级别日志,并有可能启用SQL语句以帮助调试。为了这样做,我将以下内容添加到我的application.properties

spring.jpa.properties.hibernate.show_sql=false
spring.jpa.properties.hibernate.use_sql_comments=true
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.properties.hibernate.type=trace
spring.jpa.show-sql=true
logging.level.org.hibernate=TRACE

这里会有很多输出,但是您会对幕后发生的事情有一个很好的了解。

第三,对我学习如何使用@Transactional的最重要部分是,如果在同一交易范围内,则每个呼叫都会创建一个新的会话 - 或重新使用现有会话。有关此的示例,请参阅上面的文档。

最新更新