4 Replies Latest reply on Jun 7, 2006 12:37 PM by David Owens

    EJB3/EntityManager/Transactions and LazyInitializationExcept

    David Owens Newbie

      So I implemented an stateless session bean which in turn uses an entity manager. Under that is hibernate. I am once again trying to answer the age old question of how do I get around the LazyInitializationException.

      The code in my struts action looks like this:

       PetServiceInterface psi = null;
       try {
       InitialContext ctx = new InitialContext();
       psi = (PetServiceInterface) ctx.lookup("PetService/local");
       } catch (Exception e) {
       e.printStackTrace();
       }
      
       Person customer = psi.findPerson(12);
       OwnerForm of = (OwnerForm) form;
       of.setName(customer.getName());
       of.setAge(customer.getAge());
       of.setPets(customer.getPets());
      
       return (mapping.findForward("page"));


      My ejb looks like this:

      @Service(objectName = "whatever:service=PetService")
      @Stateless
      public class PetService implements PetServiceInterface {
      
       @PersistenceContext(unitName="pet") EntityManager em;
       public Person findPerson(int id) {
       return em.find(Person.class, Integer.valueOf(id));
       }


      Now in my jsp I iterate the pets on the customer which throws a LazyInitializationException because the session is already closed.

      Looking at secion 4.1.1 in
      http://www.hibernate.org/hib_docs/entitymanager/reference/en/html_single/#transactions
      it says this:

      This is the default EJB3 persistence model in a Java EE environment (JTA bounded, transaction-scoped persistence context); injected (or looked up) entity managers share the same persistence context for a particular JTA transaction. The beauty of EJB3 is that you don't have to care about that anymore and just see data access through entity manager and demaraction of transaction scope on session beans as completely orthogonal.


      Since I'm running JBoss 4.0.4.GA.Patch1, and using EBJ3, I was hoping the container would take care of the transactions for me. In other words, I was hoping the servlet request then response would all be in a JTA transaction, and the EJB would inherit that transaction, and the EntityManager would then inherit the same one, and so on.

      If I mark the ejb with:
      @TransactionAttribute(TransactionAttributeType.MANDATORY)

      I will get an exception because there is no transaction. So am I missunderstanding the quore about not needing to care about the transaction, or am I missing something in my setup to let the container manage it all for me?

      Note: Everything else works in the code as long as I stay in the action. In other words, I get a customer, set the values, and the action returns without error as expected.

      Before I was using a ServletFilter to manage the hibernate session, but I was hoping to get rid of that code.

      Any help would be greatly appreciated.

        • 1. Re: EJB3/EntityManager/Transactions and LazyInitializationEx
          Tamir Efron Newbie

          don't close your session, and if you do, just call update into a new session before you acceess a lazy property...

          • 2. Re: EJB3/EntityManager/Transactions and LazyInitializationEx
            David Owens Newbie

             

            "tefron" wrote:
            don't close your session, and if you do, just call update into a new session before you acceess a lazy property...


            That's just it, I don't want to close the transaction, but when I leave the ejb, the transaction is closed for me.

            • 3. Re: EJB3/EntityManager/Transactions and LazyInitializationEx
              Frank Stolle Newbie

              You need to open a transaction via UserTransaction in your Struts-Action, so that the SessionBean-call will be inside your own transaction.

              • 4. Re: EJB3/EntityManager/Transactions and LazyInitializationEx
                David Owens Newbie

                I was hoping jboss would start the transaction for me, when my http request happened, and then close it when it was done. But no go. So I wrote the servlet filter below, and it all works. I just hoped the container would take care of it for me. Maybe in the future, when we have more time, I will try out Seam.

                public class TransactionFilter implements Filter {
                 FilterConfig config = null;
                
                 public void init(FilterConfig arg0) throws ServletException {
                 config=arg0;
                 }
                
                 public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
                
                 InitialContext ctx;
                 UserTransaction ut = null;
                 try {
                 ctx = new InitialContext();
                 ut = (UserTransaction) ctx.lookup("UserTransaction");
                 if(Status.STATUS_NO_TRANSACTION == ut.getStatus()) {
                 ut.begin();
                 } else {
                 ut = null;
                 }
                 } catch (Exception e) {
                 config.getServletContext().log("Error getting context and beginning transaction", e);
                 }
                
                
                 try {
                 chain.doFilter(request, response);
                 if((ut != null) && (Status.STATUS_ACTIVE == ut.getStatus())) {
                 ut.commit();
                 }
                 } catch (Exception e) {
                 config.getServletContext().log("Error in filter or commit", e);
                 try {
                 if((ut != null && (Status.STATUS_ACTIVE == ut.getStatus()))) {
                 ut.rollback();
                 }
                 } catch (Exception e1) {
                 config.getServletContext().log("Error rolling back exception", e1);
                 }
                 } finally {
                
                 }
                 }
                
                 public void destroy() {
                 }
                }