2011-03-25 50 views
1

在使用EclipseLink和DB上的所有業務邏輯的3層Web項目中,我需要在每個存儲的調用之前和之後執行存儲過程,無論是過程還是函數,都在同一個會話中。這是一個管理決定,我對此無能爲力。 所以我轉向session customization with Event Listeners,但它不工作。EclipseLink會話自定義 - 錯誤

這裏是我在Session Customizer中的代碼: 注意:「wrapper」是一個自定義類,它包裝了一個StoredProcedureCall,「log」是一個log4j Logger。

SessionEventAdapter adapter = new SessionEventAdapter() { 
    @Override 
    public void preExecuteQuery(SessionEvent event) { 
     log.debug("Setting environment parameters before query execution."); 

     [some business code...] 

     StoredProcedureCall call = wrapper.generateCall(); 

     DatabaseQuery query = new DataModifyQuery(call); 

     event.getSession().executeQuery(query); 

     preExecuteQuery(event); 
    } 

    @Override 
    public void postExecuteQuery(SessionEvent event) { 
     log.debug("Releasing environment parameters after query execution."); 

     [some business code...]   

     StoredProcedureCall call = wrapper.generateCall(); 

     DatabaseQuery query = new DataModifyQuery(call); 

     event.getSession().executeQuery(query); 

     postExecuteQuery(event); 
    } 
}; 

session.getEventManager().addListener(adapter); 

我得到的是記錄的該行「設置環境參數......」被重複不少於600-800倍,然後我得到一個堆棧溢出錯誤。我不知道爲什麼preExecuteQuery無限循環。我錯過了什麼嗎?據我所知,我做的和EclipseLink wiki中的完全一樣。在你問之前,行爲是否與最後一行preExecuteQuery(event);相同。

我還假設使用preExecuteQuery和postExecuteQuery事件是在每次查詢前後都將調用放入同一會話的正確位置,但也許我錯了。我也會嘗試PostAcquireUnitOfWork和PreCommitUnitOfWork事件。

任何想法?感謝您的幫助。

回答

0

我想你的電話executeQuery()觸發preExecuteQuery()postExecuteQuery()再次。如果是這樣,你可以做這樣的事情:

SessionEventAdapter adapter = new SessionEventAdapter() { 
    private ThreadLocal<Boolean> inListener = new ThreadLocal<Boolean>(); 

    @Override 
    public void preExecuteQuery(SessionEvent event) { 
     if (inListener.get() == Boolean.TRUE) return; 
     inListener.set(true); 
     try { 
      ... 
     } finally { 
      inListener.remove(); 
     } 
    } 

    @Override 
    public void postExecuteQuery(SessionEvent event) { 
     if (inListener.get() == Boolean.TRUE) return; 
     inListener.set(true); 
     try { 
      ... 
     } finally { 
      inListener.remove(); 
     } 
    } 
}; 
+0

你說得對,謝謝。 – Alessandro 2011-03-28 09:25:41

1

最好檢查查詢類型,如果查詢是DataModifyQuery那麼不執行該事件。爲了更精確地在你的代碼中,你可以添加一個屬性到DataModifyQuery中進行檢查,以便只有事件查詢不會被執行。

此外,您必須刪除調用「postExecuteQuery(event);」和「preExecuteQuery(event);」因爲此代碼將重複回調該事件代碼,始終導致堆棧溢出。

+0

如果您指的是我的解決方案,請注意該標記爲「ThreadLocal」,因此它不會干擾其他線程。 – axtavt 2011-03-28 13:24:54

+0

我很抱歉,我錯過了它是ThreadLocal。不過,我希望檢查查詢類型和查詢屬性,如果需要將提供更好的解決方案。 – 2011-03-29 19:48:22