防止同一对象与hibernate中的两个不同会话相关联

时间:2010-02-17 11:21:37

标签: java hibernate session

使用jsf 1.2,hibernate,richfaces 3.3.0GA和facelets。

我在我的支持bean中有这个代码:

public List<Rater> getFreeRaters(){
    GP myGP = (GP) user;
    update(myGP.getContract());
    ArrayList<Rater> raters = new ArrayList<Rater>(myGP.getContract().getRaters());
    ArrayList<Rater> selectedRaters = this.getSelectedRaters();
    raters.removeAll(selectedRaters);
    return raters;

}

和UI的这段代码:

<a4j:form id="gradersForm" ajaxSingle="true">
    <rich:listShuttle sourceValue="#{user.gradersTab.freeRaters}" id="gradersTab_listShuttle"
    targetValue="#{user.gradersTab.selectedRaters}" var="rater" listsHeight="150"
        sourceListWidth="130" targetListWidth="130" sourceCaptionLabel="Available Items"
        targetCaptionLabel="Currently Active Items" > 
        <rich:column>
            <h:outputText value="#{rater.username}"></h:outputText>
        </rich:column>
    </rich:listShuttle>         
    <a4j:commandButton value="Save"></a4j:commandButton>

</a4j:form>

这是我的会话过滤器:

public class HibernateSessionRequestFilter implements Filter {

private static Log log = LogFactory.getLog(HibernateSessionRequestFilter.class);

private SessionFactory sf;

public void doFilter(ServletRequest request,
                     ServletResponse response,
                     FilterChain chain)
        throws IOException, ServletException {
    HttpServletResponse resp= (HttpServletResponse) response;
    try {
        log.info("Starting a database transaction");
        Session session = sf.getCurrentSession();
        session.beginTransaction();

        // Call the next filter (continue request processing)
        chain.doFilter(request, resp);

        // Commit and cleanup
        log.info("Committing the database transaction");

        session.getTransaction().commit();


    } catch (StaleObjectStateException staleEx) {...

当UI通过AJAX同时重新渲染两次或更多时,问题就出现了。作为两个不同的请求,每个请求获得Session,并且试图同时将对象附加到它们两者,因为它们都没有时间完成并且session.close(),所以hibernate抛出一个异常 org.hibernate.HibernateException: Illegal attempt to associate a collection with two open sessions

有任何建议可以防止这种情况发生吗?感谢。

更新:web.xml中

<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"       xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-   app_2_5.xsd">
<display-name>eyeprevent</display-name>
<context-param>
<param-name>javax.faces.CONFIG_FILES</param-name>
<param-value>/WEB-INF/faces-config.xml</param-value>
</context-param>
<context-param>
<param-name>javax.faces.DEFAULT_SUFFIX</param-name>
<param-value>.xhtml</param-value>
</context-param>
<context-param>
<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
<param-value>server</param-value>
</context-param>
<context-param>
<param-name>facelets.LIBRARIES</param-name>
<param-value>/WEB-INF/functions.taglib.xml</param-value>
</context-param>
<context-param>
<param-name>org.richfaces.SKIN</param-name>
<param-value>#{user.skin}</param-value>
</context-param>
<context-param>
<param-name>org.richfaces.CONTROL_SKINNING</param-name>
<param-value>enable</param-value>
</context-param>
<filter>
<filter-name>HibernateFilter</filter-name>
<filter-class>com.eyeprevent.util.HibernateSessionRequestFilter</filter-class>
</filter>
<filter>
<display-name>RichFaces Filter</display-name>
<filter-name>richfaces</filter-name>
<filter-class>org.ajax4jsf.Filter</filter-class>
</filter>
<filter-mapping>
<filter-name>HibernateFilter</filter-name>
<url-pattern>/pages/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>HibernateFilter</filter-name>
<url-pattern>/upload/*</url-pattern>
</filter-mapping>

<filter-mapping>

<filter-name>richfaces</filter-name>
<servlet-name>Faces Servlet</servlet-name>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
<dispatcher>INCLUDE</dispatcher>
</filter-mapping>
<listener>
<listener-class>com.sun.faces.config.ConfigureListener</listener-class>
</listener>
<listener>
<listener-class>com.eyeprevent.util.MySessionListener</listener-class>
</listener>
<servlet>
<display-name>EPConnectServlet</display-name>
<servlet-name>EPConnectServlet</servlet-name>
<servlet-class>com.eyeprevent.servlets.EPConnectServlet</servlet-class>
<init-param>
<param-name>imagePath</param-name>
<param-value>/home/pako/images</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet>
<servlet-name>imageServlet</servlet-name>
<servlet-class>com.eyeprevent.servlets.ImageServlet</servlet-class>
<init-param>
<param-name>imagePath</param-name>
<param-value>/home/pako/images</param-value>
</init-param>
</servlet>
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>EPConnectServlet</servlet-name>
<url-pattern>/upload/EPConnectServlet</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>imageServlet</servlet-name>
<url-pattern>/image/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>0</session-timeout>
</session-config>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.xhtml</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
<welcome-file>pages/login.xhtml</welcome-file>
</welcome-file-list>
<error-page>
<error-code>404</error-code>
<location>/pages/error.xhtml</location>
</error-page>
<error-page>
<error-code>401</error-code>
<location>/pages/unauthorized.xhtml</location>
</error-page>
<login-config>
<auth-method>BASIC</auth-method>
</login-config>
</web-app>

1 个答案:

答案 0 :(得分:2)

显然使用merge代替update似乎可以解决问题...

请记住,merge会返回新更新的实例,因此您应该

myInstance = (myInstanceClass) Session.merge(myInstance);