2017-05-05 71 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

相關問題