2011-03-25 52 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