6 Replies Latest reply on Jul 15, 2008 5:56 PM by pmuir

    EntityManager not thread-safe?

    fbarth

      Hi there!
      I'm currently developing some webProject. The main layout consists of some contentboxes that are included (with ui:include) and display their information.
      As some of these boxes had a rather large loading time, I call a method in the backing function, that generates the data for the content and than this data is display asynchronously. I got this to work by polling the bean once with the evaluation method as action and than rerendering the displayed content.
      This works fine and without problems for each of my boxes.


      When I combine some of these boxes on one page I get some strange Excpetions.  I will list some of these Excpetions now, they apear randomly:



      • hibernateExcpetions that some Collection has been flushed twice to

      • persistence / jdbc exceptions that a connnection cannot be opened

      • transaction exceptions that transactions are already closed



      When testing with one or two of this boxes everything is fine, with more this things happen. I Inject the entityManagaer with


      @In
      EntityManager entityManager



      in each of the boxes. The contexxt of this EM is managed by seam. Is there a possibility that the parallel calls from the included box-backing beans affect each ohter and thus lead to this strange exception-mix?

        • 1. Re: EntityManager not thread-safe?
          bravocharlie.seam.signup.benny.me.uk

          What scope are your components?  Post some code?

          • 2. Re: EntityManager not thread-safe?
            fbarth

            The box-backing bean (I like this triple-b-term ;)) is page scoped.
            The CollabfilterBean in this example-box is not used in the other boxes. The data in the other boxes is generated from standard queries, e.g.:


            Query query = entityManager.createQuery(
                      "select new "+WatchListWrapper.class.getCanonicalName()+"(loc) " + 
                      " FROM User as u" +
                      " join u.watchedLocations as loc" +
                      " WHERE u=?1" +
                      " ORDER BY loc.modified desc")
            query.setParameter(1, user));
                 
                      results = query.getResultList();                              



            This is the backing logic for the contentBox I'm talking about.


            @Name("userRecBox")
            @Scope(ScopeType.PAGE)
            public class UserRecBox implements ContentBox<UserRecWrapper>{
            
                 @Logger
                 Log log;
            
                 @In
                 User user;
                 
                 @In
                 Identity identity;
                 
                 @In(create = true)
                 private CollabFilterBean collabFilter;
            
                 private List<UserRecWrapper> results = new ArrayList<UserRecWrapper>();
            
                 public List<UserRecWrapper> getResults() {
            
                      return results;
                 }
            
                 public Long getResultCount() {
            
                      return new Long(results.size());
                 }
            
                 public Object evaluate() {
                 if (identity.isLoggedIn()) {
                           results = new ArrayList<UserRecWrapper>();
                                HashMap<Location, Double> recom = collabFilter.getRecommendationsForUser(user);
                           for (Entry<Location, Double> entry : recom.entrySet()) {
                                results.add(new UserRecWrapper(entry.getKey(), entry.getValue()));
                           }
                                     
                           
                      }
                      return false;
                 }
            
            
            }




            The collabfilterBean that generates the data for the box: (just the interesting parts)


            Name("collabFilter")
            @Scope(ScopeType.APPLICATION)
            public class CollabFilterBean implements CollabFilter {
            
                 
                 
                 @Logger
                 Log log;
            
                 @In(create = true)
                 EntityManager entityManager;
            (...)



            and finally the xhtml-box-code (again, just interesting parts)


                 <h:form>
                           <a4j:jsFunction name="userRec_eval" action="#{userRecBox.evaluate}"
                                reRender="userRecommendationResult" status="status_userRec">
                           </a4j:jsFunction>
                      </h:form>
            
            <rich:jQuery selector="document"     
                 rendered="#{identity.loggedIn}" 
                 timing="onload" 
                 query="each(function () {userRec_eval();})"/>
            
            <a4j:outputPanel id="userRecommendationResult">
                 <rich:panel rendered="#{identity.loggedIn}" style="border:0px;">
                      <h:form>
                           <rich:dataList var="recWrap" value="#{userRecBox.results}"
                                rows="#{userRecBox.resultCount}">
                                <h:outputText value="#{recWrap.location.name} #{recWrap.location.kind}" />
                                          <br />
                                <h:outputText value="("></h:outputText>
                                <h:outputText value="#{recWrap.location.description}" />
                                <h:outputText value=")"></h:outputText>
                                <br />
                                <h:outputText value="score: "></h:outputText>
                                <h:outputText value="#{recWrap.rating} " />
                           </rich:dataList>
                      </h:form>
                 </rich:panel>
            <rich:panel rendered="#{not identity.loggedIn}">
                      Not logged in!
                 </rich:panel>
            </a4j:outputPanel>
            

            • 3. Re: EntityManager not thread-safe?
              gjeudy

              EntityManager is not thread-safe but Seam will serialize concurrent requests made to CONVERSATION scope or SESSION scoped beans so it should not matter.


              In your case you inject an entityManager in an APPLICATION scoped bean, chances are that the entityManager is also in APPLICATION scope and that would explain partly the behavior.


              Can you post your entityManager config in components.xml ?

              • 4. Re: EntityManager not thread-safe?
                pmuir

                The scope of the component into which you inject a component doesn't affect the scope of the injected component.

                • 5. Re: EntityManager not thread-safe?
                  gjeudy

                  True, but does it also apply when the injected component does not exist and is autocreated as in:


                  @In(create=true)


                  ?

                  • 6. Re: EntityManager not thread-safe?
                    pmuir

                    No. The scope of the injected component is never altered by injection.