1 2 Previous Next 21 Replies Latest reply on Nov 24, 2005 7:52 AM by renkrad

    org.hibernate.LazyInitializationException, how to access laz

    javatwo

      Hello,

      Entity A has a reference to Entity B. (OneToOne)

      @Entity
      public class A {
      // id ...

      @OneToOne(fetch=FetchType.LAZY)
      public B getB() {
      return b;
      }

      public void setB(B b) {
      this.b = b;
      }


      }

      A a = aSessionBean.getA(id);
      ...

      B b = a.getB();

      org.hibernate.LazyInitializationException: could not initialize proxy - the owning Session was closed

      when is the owning session created and closed?
      What is the right way to access Lazy property(such as B above)?

      Thank you for your help. Have a nice day.

      Dave

        • 1. Re: org.hibernate.LazyInitializationException, how to access
          neelixx

          You have to add the fetch in your query:

          Go to http://docs.jboss.org/ejb3/app-server/HibernateEntityManager/reference/en/html_single/index.html

          For more information. Specifically (copy/pasted from the web page)

          In addition, a "fetch" join allows associations or collections of values to be initialized along with their parent objects, using a single select. This is particularly useful in the case of a collection. It effectively overrides the fetching options in the associations and collection mapping metadata. See the Performance chapter of the Hibernate reference guide for more information.

          select cat from Cat as cat
          inner join fetch cat.mate
          left join fetch cat.kittens

          A fetch join does not usually need to assign an alias, because the associated objects should not be used in the where clause (or any other clause). Also, the associated objects are not returned directly in the query results. Instead, they may be accessed via the parent object. The only reason we might need an alias is if we are recursively join fetching a further collection:

          select cat from Cat as cat
          inner join fetch cat.mate
          left join fetch cat.kittens child
          left join fetch child.kittens

          Note that the fetch construct may not be used in queries called using scroll() or iterate(). Nor should fetch be used together with setMaxResults() or setFirstResult(). It is possible to create a cartesian product by join fetching more than one collection in a query (as in the example above), be careful the result of this product isn't bigger than you expect. Join fetching multiple collection roles also sometimes gives unexpected results for bag mappings, so be careful about how you formulate your queries in this case.

          • 2. Re: org.hibernate.LazyInitializationException, how to access
            redijedi

            I have run into a similar problem that appears to be a bug. Given Entity Beans A and B, Session Bean BServiceBean, and Servlet Test:

            @Entity
            @Table(name = "users")
            @SecondaryTable(name = "user_access")
            @JoinColumn(name = "user_fk")
            public class A implements Serializable {
            
             private int id;
            
             private String username;
            
             private String password;
            
             private String fname;
            
             private String lname;
            
            
             /**
             * Default constructor.
             *
             */
             public A() {
             // Default
             }
            
             /**
             * @return Returns the id.
             */
             @Id(generate = GeneratorType.TABLE)
             @Column(name = "id")
             public int getId() {
             return id;
             }
            
             /**
             * @param id
             * The id to set.
             */
             public void setId(int id) {
             this.id = id;
             }
            
             /**
             * @return Returns the username.
             */
             @Column(name = "username", secondaryTable = "user_access")
             public String getUsername() {
             return username;
             }
            
             /**
             * @param username
             * The username to set.
             */
             public void setUsername(String username) {
             this.username = username;
             }
            
             /**
             * @return Returns the password.
             */
             @Column(name = "password", secondaryTable = "user_access")
             public String getPassword() {
             return password;
             }
            
             /**
             * @param password
             * The password to set.
             */
             public void setPassword(String password) {
             this.password = password;
             }
            
             /**
             * @return Returns the fname.
             */
             @Column(name = "fname")
             public String getFName() {
             return fname;
             }
            
             /**
             * @param fname
             * The fname to set.
             */
             public void setFName(String fname) {
             this.fname = fname;
             }
            
             /**
             * @return Returns the lname.
             */
             @Column(name = "lname")
             public String getLName() {
             return lname;
             }
            
             /**
             * @param lname
             * The lname to set.
             */
             public void setLName(String lname) {
             this.lname = lname;
             }
            }
            
            
            @Entity
            @Table(name = "attributes")
            public class B implements Serializable {
            
             private int id;
            
             private String title;
            
             private A a;
            
             /**
             * Default constructor.
             */
             public B() {
             // Default
             }
            
             @Id(generate = GeneratorType.TABLE)
             @Column(name = "id")
             public int getId() {
             return id;
             }
            
             public void setId(int id) {
             this.id = id;
             }
            
             @Column(name = "title")
             public String getTitle() {
             return title;
             }
            
             public void setTitle(String title) {
             this.title = title;
             }
            
             /**
             * @return Returns the a.
             */
             @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
             @JoinColumn(name="id")
             public User getA() {
             return a;
             }
            
             /**
             * @param a The a to set.
             */
             public void setA(A a) {
             this.a = a;
             }
            }
            
            @Stateless
            @Local(BService.class)
            @Remote(BService.class)
            public class BServiceBean implements BService {
            
             @PersistenceContext(unitName = "mine")
             protected EntityManager em;
            
             public B getB(Integer bId) {
             return em.find(B.class, Integer.valueOf(bId));
             }
            }
            
            public class Test extends HttpServlet {
            
             /**
             * @see HttpServlet#doGet(HttpServletRequest,HttpServletResponse);
             */
             protected void doGet(HttpServletRequest req, HttpServletResponse resp)
             throws ServletException, IOException {
             try {
             InitialContext ctx = new InitialContext();
             BService bSvc = (BService) ctx.lookup("BService");
             B b = bSvc.getB(200);
             A a = b.getA();
             System.out.println(b.getTitle());
             System.out.println(a.getFName());
             System.out.println(a.getUsername());
             } catch (Exception e) {
             e.printStackTrace();
             }
             }
            }
            


            When the Test servlet gets a new BService instance, I do not want it to load the A belonging to B, so I set it as lazy load. However, this fails due to the multi-table mapping of A. The only way I've found to make it work is by setting fetch to eager. This is not what I want because I only want this to fetch from the db when the getA method is called.

            It seems to me that the container should know that the multi-table mapping is a single entity (since I do not see any fetch options) and pull that entire joined record when I ask B for an A. Doesn't this make sense?

            • 3. Re: org.hibernate.LazyInitializationException, how to access
              redijedi

              I forgot to mention that this situation fails in the same manner as listed in the original post:

              21:59:21,188 ERROR [LazyInitializationException] could not initialize proxy - the owning Session was closed
              org.hibernate.LazyInitializationException: could not initialize proxy - the owning Session was closed
              


              • 4. Re: org.hibernate.LazyInitializationException, how to access
                martinganserer

                Hello,

                I have the same problem with all my lazy attributes every time when I work with servlets!

                What goes wrong here? Is lazy loading not working properly, or didn't we understand how lazy loading really works with EJB3?

                Thank you for your reply!

                • 5. Re: org.hibernate.LazyInitializationException, how to access
                  elkner

                  I guess, I got an answer: em.find(...) returns lazy initialized entities if it supports lazyness. And since web is scoped/isolated from the container running the em, ...

                  • 6. Re: org.hibernate.LazyInitializationException, how to access
                    martinganserer

                    Hello,

                    after searching for the problem the whole internet ;-) I found following solution that works with servlets:

                    - Change the DAO to be @Stateful
                    - Change the injected entity manager to
                    private @PersistenceContext(type=PersistenceContextType.EXTENDED...

                    Any comments?

                    • 7. Re: org.hibernate.LazyInitializationException, how to access
                      redijedi

                      Changing the DAO to Stateful seems to be a hack. The difference between stateless and stateful should relate to the persistence of the state of the session bean, not the objects that the session bean calls out to. This is a red flag for my company, as we have large db entities that will create huge object graphs if eagerly loaded, and we use stateless session beans for the majority of our facades.

                      This behavior is a flaw IMHO in the EJB implementation.

                      • 8. Re: org.hibernate.LazyInitializationException, how to access
                        danch1

                         

                        "martin ganserer" wrote:
                        Hello,

                        I have the same problem with all my lazy attributes every time when I work with servlets!

                        What goes wrong here? Is lazy loading not working properly, or didn't we understand how lazy loading really works with EJB3?

                        Thank you for your reply!


                        When you traverse the lazy loaded associations in servlet-land, you're outside of the transaction that loaded them. Lazy loading is not supported in this fashion.

                        For a large application, this is the behavior you want - supporting lazy loading outside of the transaction brings up questions: should changes be propogated? When/How often do you allocate DB connections for the lazy-loading? If you wanted all that data, why didn't you get it in one transaction?

                        Obviously, these questions can be answered, but the answers will tend to be application specific. Maybe in a couple of years we'll have seen enough of the real answers and enough good solutions to be able to make the behavior standard.

                        Traditional ways around this are to tune your service layer around the needs of your application layer, such that there are service methods that 'know' what data the caller will need.
                        Another thought is for the service layer to support the notion of a 'facet' such that when the UI layer calls into the service, it indicates which 'facets' it will require and the service layer simply excercizes the associations corresponding to those facets.

                        In more modern times ;), we've had the OpenSessionInView ha-er servlet filter. That seems to be what the statefull bean/extended persistence context stuff is doing, but I haven't looked at the internals there.

                        • 9. Re: org.hibernate.LazyInitializationException, how to access
                          danch1

                           

                          "redijedi" wrote:
                          Changing the DAO to Stateful seems to be a hack. The difference between stateless and stateful should relate to the persistence of the state of the session bean, not the objects that the session bean calls out to. This is a red flag for my company, as we have large db entities that will create huge object graphs if eagerly loaded, and we use stateless session beans for the majority of our facades.

                          This behavior is a flaw IMHO in the EJB implementation.


                          So how do you manage this in non-EJB3 web applications?

                          • 10. Re: org.hibernate.LazyInitializationException, how to access
                            redijedi

                             

                            "danch" wrote:

                            So how do you manage this in non-EJB3 web applications?


                            We do not use entity beans for this reason (among others). We have been forced to write our own daos. I am evaluating the new model and am finding it insufficient based on this issue.

                            • 11. Re: org.hibernate.LazyInitializationException, how to access
                              redijedi

                               

                              "danch" wrote:

                              When you traverse the lazy loaded associations in servlet-land, you're outside of the transaction that loaded them.


                              This seems to be a situation that should be handled transparently. If I create a property of an entity bean that should be lazy-loaded on access, I should expect this to work as advertised. The reality (as you've explained) is that the lazy-loaded property in bean b is useless outside of the session bean that accesses the bean b. Therefore, if I do not use all of the properties on bean b, including the lazy loaded bean a, within the session beans business method, the entity bean is less useful.

                              That's disappointing since it reduces the utility of the entity bean. Based on the info presented, I will have to call the facade from my servlet, get bean a, then call another method on the facade to get bean b based on an id from bean a, then perform some logic.

                              This is a very common use case. The other option is to eager load it. However, then everytime this bean is called through this facade, it will contain all of that data regardless of whether or not the client uses it. This can be expensive in situations where every db access is precious.

                              Altogether, it seems that entity beans are, again, no substitue for straight jdbc, as tedious as that is.

                              • 12. Re: org.hibernate.LazyInitializationException, how to access
                                redijedi

                                Another thing to note is that the lazy-loading outside of the transaction argument is not altogether true from what I've seen.

                                I know from testing that if I call a session bean method to get an entity, and this entity has a lazy loaded property, I can access this property after the initial call to the session bean. This situation hat has one level of lazy loading outside the transaction works. If, however, the lazy loaded property of said entity has a lazy loaded property of its own, it will fail. This is what I am seeing. I do not understand why it works on one level and not another.

                                • 13. Re: org.hibernate.LazyInitializationException, how to access
                                  martinganserer

                                  Hello redijedi,

                                  maybe it is a hack for you. And using stateful session beans for every dao is really not what I considered. This would result in a big overhead for all stateful beans that nobody wants.
                                  In my post I only wanted to show one possible easy to handle solution!

                                  On the other hand building a service layer that knows how to build a bean
                                  that will be sent to the client jsp or SWING app is another possible solution that I might implement for my app.

                                  Regards

                                  • 14. Re: org.hibernate.LazyInitializationException, how to access
                                    gavin.king

                                     

                                    "redijedi" wrote:
                                    Changing the DAO to Stateful seems to be a hack. The difference between stateless and stateful should relate to the persistence of the state of the session bean, not the objects that the session bean calls out to. This is a red flag for my company, as we have large db entities that will create huge object graphs if eagerly loaded, and we use stateless session beans for the majority of our facades.

                                    This behavior is a flaw IMHO in the EJB implementation.


                                    Nonsense.

                                    1) No, you should of course not fetch data from a relational database by starting arbitrary transactions to fetch arbitrarily small chunks of data using tiny finegrained requests across the network. This is equivalent to remote access to EJB2 entity beans, is known to not scale, does not allow well-defined transaction isolation semantics, and was the reason why the session facade pattern was invented. Ad hoc lazy fetching of associations outside of a well defined transaction context is utterly evil.

                                    2) If you want a long persistence context, a stateful bean is EXACTLY the way to express that. The pc is state associated with the client of the bean. That, not coincidentally, is the definition of a stateful bean. A stateless bean has no state associated with the client.

                                    3) You need to read a book like Hibernate in Action which explains how to manage fetching of data and persistence contexts using ORM, before trying to blame the EJB spec for your problems. In particular, you will need to understand the concept of FETCH JOIN, and the concept of open-session-in-view.

                                    4) We recently released Seam, which includes the notion of a Seam-managed persistence context, which is able to completely eliminate any problems with LIEs for well-designed applications.


                                    1 2 Previous Next