2017-05-05 410 views
1

我的Spring批处理作业每5分钟启动一次 - 基本上它读取一个字符串,将该字符串用作sql查询中的参数,并打印出结果sql结果列表。主要是它似乎是确定运行,但我发现在我的日志零星错误每隔5-10运行Spring批处理无法打开JPA EntityManager进行事务处理;嵌套异常是java.lang.IllegalStateException:事务已经激活

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已经注入到每个步骤的事务管理器 - 但是当我这样做时,我更频繁地看到'transaction already active'错误。

有关如何解决此问题的任何建议赞赏,谢谢!

+0

错误出现在'c.u.r.s.AgentCollectorServiceImpl'中,但没有提供源代码。另外,请考虑一个最小的,可验证的例子。当你得到这些,你可能已经解决了这个问题。 –

+0

@KarlNicholas显示如何启动作业的第一个代码块来自AgentCollectorServiceImpl。我编辑了我的问题来表明这一点。 – user619804

+0

@KarlNicholas - 这是基本的工作代码 - 我只是看到这个事务已经存在每5-10次出错一次 – user619804

回答

0

@Transactional表示法建立一个事务性范围,它规定事务开始和结束的时间,也称为边界。如果您在此范围之外进行操作,您将收到错误信息。

首先,我发现这个位文件对Spring的事务中最有帮助的:http://docs.spring.io/spring-framework/docs/4.2.x/spring-framework-reference/html/transaction.html专门this section

其次,您可能希望启用跟踪级别日志和潜在的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 

将有输出的ALOT在这里,但你会得到什么幕后发生的事情是一个好主意。

第三,也是我学习如何使用@Transactional最重要的部分是,每次调用DAO都会创建一个新的会话 - 或者 - 如果在相同的事务范围内重用现有会话。有关这方面的示例,请参阅上述文档。

+0

我的DAOImpl类用@Transactional注释。我只从Spring Batch作业中调用该类的一个方法。似乎SPring应该很容易管理我的交易。 – user619804

+0

@ user619804 - 我也认为同样的事情,但事务性注释的出现比出现更多 –

+0

一个问题是Spring Batch应该注入自己的事务管理器。我试图删除@Transactional,但它似乎没有解决问题 – user619804

相关问题