-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 19 posts ]  Go to page 1, 2  Next
Author Message
 Post subject: LazyLoadException with Swing + Spring + Hibernate
PostPosted: Fri Aug 05, 2005 7:38 am 
Newbie

Joined: Fri Aug 05, 2005 7:26 am
Posts: 17
Location: Santa Barbara d´Oeste SP Brasil
Hello Guys!

I´m having the tradicional problem of LazyLoadingException in my Swing application.

Let me explain how I´m working.

I have a DAO interface, called GenericDAO, and one implementation in Hibernate, called Hibernate3BasedDAO. In my Spring configuration, I have this:

Code:
<bean id="genericDAO" class="org.springframework.aop.framework.ProxyFactoryBean">
    <property name="target">
      <bean class="com.mypackage.genericdao.impl.Hibernate3BasedDAO">
       <property name="sessionFactory">
         <ref bean="xtoSessionFactory"/>
       </property>
      </bean>
    </property>
    <property name="proxyInterfaces">
      <value>com.mypackage.genericdao.GenericDao</value>
    </property>
  </bean>



So, when I did in my code springFactory.getBean("genericDAO"), I get one instance of Hibernate3BasedDAO.

Then, I have one interface of service, called AttributeService, and his implementatiom AttributeServiceImpl. In my Spring configuration, I have this:

Code:
  <bean id="attributeService"
        class="org.springframework.aop.framework.ProxyFactoryBean">
    <property name="target">
     <bean class="com.mypackage.xto.attributebuilder.business.impl.AttributeServiceImpl">
       <property name="dao">
         <ref bean="genericDAO"/>
       </property>
     </bean>
    </property>
    <property name="proxyInterfaces">
      <value>com.mypackage.xto.attributebuilder.business.AttributeService</value>
    </property>
  </bean>

So, when I did in my code springFactory.getBean("attributeService"), I get one instance of AttributeServiceImpl, with an instance of HibernateBased3DAO.

In the AttributeService interface, I have a method called findAllAttributes, in the implementation, I do the follow:

Code:
public List<Attribute> fildAllAttributes() {
   List<Attribute> result;
   
   result = dao.findByQuery("findAllAttributesQuery", Attribute.class);
   
   return result;
}


What happened in this method? I just get all Attributes from my database.

Ok... for now, we are ok... we did some Unit tests and everthing works fine.

Then... we started to do our Swing screens, and we want a screen that list all Attributes in a JTable, so, we have something like this:

Code:
public class ListAttributesFrame extends JFrame {


    public void ListAttributesFrame() {
       // .. Swing initialization stuff
       
       createGui();
    }
   
       
    private void createGui() {
       AttributeService service;
       List<Attribute> attributes;
       TableModel tableModel;
       JTable table;

       // Get the attributeService       
       service = springFactory.getBean("attributeService");
       
       // get all attributes
       attributes = service.findAllAttributes();
       
       // create the tableModel
       tableModel = new AttributeTableModel(attributes); // this is my customized table model to show the attributes
       
       // create the table and put in the container
       JTable table = new JTable(tableModel);
       
       this.getContentPane().add(table);
       
    }

}

When we run this class, what happened? Wow!! He have a list of all attributes in a table! Great!

Now I want to show in a dialog, some properties of my attributes, so, we did this:

Code:
public class ListAttributesFrame extends JFrame {


    public void ListAttributesFrame() {
       // .. Swing initialization stuff
       
       createGui();
    }
   
       
    private void createGui() {
       AttributeService service;
       List<Attribute> attributes;
       final TableModel tableModel;
       final JTable table;

       // Get the attributeService       
       service = springFactory.getBean("attributeService");
       
       // get all attributes
       attributes = service.findAllAttributes();
       
       // create the tableModel
       tableModel = new AttributeTableModel(attributes); // this is my customized table model to show the attributes
       
       // create the table and put in the container
       table = new JTable(tableModel);
       
       this.getContentPane().add(table);
       
       // Button to show the attribute properties
       JButton button = new JButton("Show Details");
       button.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
               
                Attribute attribute;
               
                int row = table.getSelectedRow();
               
                if (row > -1) {
                attribute = tableModel.getAttribute(row);

                JOptionPane.showMessageDialog(null, "The attribute arguments size is: "+attribute.getArguments().size());

                }
       
            }
          
       });
       this.getContentPane().add(button);
       
    }

}


Well... looking the code, we guess that we are Ok, right?

Wrong!

When I hit in the button "Show Details", I have the famous LazyLoadException, because the session has been closed in the attribute service, because the session just stay open when the transaction is open, when the transaction closes, the session are closed too.

Now, my question:

Which is the best way to handle this Error in my application? Any ideas?

PS: I´m using Hibernate 3.0.5, Spring 1.2.2 and Java 1.5

Thanks in advanced!
Paulo Sigrist


Top
 Profile  
 
 Post subject:
PostPosted: Fri Aug 05, 2005 9:41 am 
Expert
Expert

Joined: Thu Sep 04, 2003 8:23 am
Posts: 368
You can look at http://www.hibernate.org/124.html

Maybe you can call a new method
Code:
service.getAttributeDetails(attribute)

when you want to see the details of an attribute.
The other approach would be to use a long session as discussed in the hibernate in action book. With this option you open the session for all your gui life and you use disconnect / reconnect between each call. I think this way of thinking is not compatible with spring.

Seb


Top
 Profile  
 
 Post subject:
PostPosted: Fri Aug 05, 2005 9:57 am 
CGLIB Developer
CGLIB Developer

Joined: Thu Aug 28, 2003 1:44 pm
Posts: 1217
Location: Vilnius, Lithuania
Just retrieve "id" from "tableModel" and try to load "attribute" in new transaction (or in the same if transaction is not finished).

Code:
attribute = service.findAttributeById(tableModel.getId(row));


Top
 Profile  
 
 Post subject:
PostPosted: Fri Aug 05, 2005 10:05 am 
Beginner
Beginner

Joined: Tue Jan 18, 2005 9:37 am
Posts: 29
Location: The Netherlands
Quote:
When I hit in the button "Show Details", I have the famous LazyLoadException, because the session has been closed in the attribute service, because the session just stay open when the transaction is open, when the transaction closes, the session are closed too.


Well, I can tell you that in a webapplication there is a design pattern to store the session in a threadLocal object so each thread has it's own session.
This session is openened when the request is made and closed after the request is completely finished (for example by using a http filter).

In your situation you can choose to do the same or make sure that you open and close a new session each time you need to access transient property's or dao objects.
A 'dirty' trick is to access the associated objects when the session is still open. this causes the objects to be loaded from the db.

Good luck.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Aug 05, 2005 10:07 am 
Newbie

Joined: Fri Aug 05, 2005 7:26 am
Posts: 17
Location: Santa Barbara d´Oeste SP Brasil
scesbron wrote:
The other approach would be to use a long session as discussed in the hibernate in action book. With this option you open the session for all your gui life and you use disconnect / reconnect between each call. I think this way of thinking is not compatible with spring.


This was our first try to fix our problems.... but, like the documentation says, we have to avoid this approach for many reasons. One problem that we had, was that in one moment of the application, we was trying do get some objects from the database and update other and an exception was threw telling us that the object that we was updating was invalid. But we didn´t call the update method yet... Hibernate did this because the objects that we was getting from the database had a relation with this object.

Quote:
Code:
service.getAttributeDetails(attribute)


I undestood what you suggested... but why to do this if the object should be previously loaded when I did the service.findAllAttributes.

Imagine that I don´t using Hibernate, I using pure JDBC connection, or other persistent framework. The service.getAttributeDetails(attribute) is just to "fix" something that hibernate do. And other thing, I´ll have to put this service.getAttributeDetails(attribute) or something like this in all button action performed... and the get attribute details is just one of the many others LazyLoadExceptions that we have ;)

But.. thanks for your help!!

PS: Sorry my english mistakes ;)


Top
 Profile  
 
 Post subject:
PostPosted: Fri Aug 05, 2005 10:11 am 
Newbie

Joined: Fri Aug 05, 2005 7:26 am
Posts: 17
Location: Santa Barbara d´Oeste SP Brasil
BasvdB wrote:
Well, I can tell you that in a webapplication there is a design pattern to store the session in a threadLocal object so each thread has it's own session.
This session is openened when the request is made and closed after the request is completely finished (for example by using a http filter).

In your situation you can choose to do the same or make sure that you open and close a new session each time you need to access transient property's or dao objects.
A 'dirty' trick is to access the associated objects when the session is still open. this causes the objects to be loaded from the db.

Good luck.


This doesn´t work because in the webapplication, when we attach the session in the threadlocal, all the code of the request run in the same thread. But in swing the things doesn´t work like this, when I hit in the button, an EventQueueThread (or other name like this) is that will run the code... is another thread, with others thread local and... other sessions...


Top
 Profile  
 
 Post subject:
PostPosted: Fri Aug 05, 2005 10:14 am 
Newbie

Joined: Fri Aug 05, 2005 7:26 am
Posts: 17
Location: Santa Barbara d´Oeste SP Brasil
baliukas wrote:
Just retrieve "id" from "tableModel" and try to load "attribute" in new transaction (or in the same if transaction is not finished).

Code:
attribute = service.findAttributeById(tableModel.getId(row));


This is almost the same what scesbron replies... and my arguments to don´t use this are the same... why get the object again from the database if I already get it?


Top
 Profile  
 
 Post subject:
PostPosted: Fri Aug 05, 2005 10:48 am 
Expert
Expert

Joined: Thu Sep 04, 2003 8:23 am
Posts: 368
Because during the first call you don't get all the object but just a part.
If you want to load all the object in the getList method, you can initialize your set by invoking them
Code:
attribute.getMyDetails()

thus you don't have your lazy exception after in you detail gui.
But this is not efficient because when you show you attributes in your lists, you don't have to retrieve all the details.

You have to choose between load all the object in the first call or load only a part and do another call when you want the details. Which solution you choose is based on the ratio size of the details/percentage of details viewed

HTH

Seb


Top
 Profile  
 
 Post subject:
PostPosted: Fri Aug 05, 2005 11:47 am 
Newbie

Joined: Fri Aug 05, 2005 7:26 am
Posts: 17
Location: Santa Barbara d´Oeste SP Brasil
scesbron wrote:
You have to choose between load all the object in the first call or load only a part and do another call when you want the details. Which solution you choose is based on the ratio size of the details/percentage of details viewed



But who should do this is the Hibernate, with your LazyLoad....


Looking the API, I found the method lock(object, lockmode) of the Session object. Doing some tests, this works fine, but, in the architecture that I´m using, when I can attach the object with the current session of the Thread?

Thanks


Top
 Profile  
 
 Post subject:
PostPosted: Fri Aug 05, 2005 12:14 pm 
Expert
Expert

Joined: Thu Sep 04, 2003 8:23 am
Posts: 368
It's not an Hibernate choice but a design choice.

If you use the lock method, you do a pessimist lock in the database which is not the better way to do (optimistic locking with versionning is better).

When you show your list, you have to choose if you want to load the entire object (if so you have to initialize your associations in your service) or just the data you need for your list (I think this is the better way).
If you choose the second solution, you will have one more call to the database. You must put the cost of this second call in relation with the cost of the extra load you do with the primer solution.

You can decrease the cost of your second call by putting your attribute in the second level cache.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Aug 05, 2005 1:21 pm 
CGLIB Developer
CGLIB Developer

Joined: Thu Aug 28, 2003 1:44 pm
Posts: 1217
Location: Vilnius, Lithuania
Do not close session before to initialize object or open new one if session was closed, proxy needs valid session and transaction to access database. Is it so unexpected ?


Top
 Profile  
 
 Post subject:
PostPosted: Wed Aug 10, 2005 8:07 am 
Newbie

Joined: Fri Aug 05, 2005 7:26 am
Posts: 17
Location: Santa Barbara d´Oeste SP Brasil
I´m back! ;)

After some others problems with the project, we back to this big problem!!



baliukas wrote:
Do not close session before to initialize object or open new one if session was closed, proxy needs valid session and transaction to access database. Is it so unexpected ?


I can´t do this because I´m not the "owner" of the session. In my Hibernate3BasedDao, my method find is like this:

Code:
   
   private HibernateTemplate hibernateTemplate
   .
   .
   .
    public void setSessionFactory(SessionFactory sessionFactory) {
        this.hibernateTemplate = new HibernateTemplate(sessionFactory, false);
    }

    public List findAll(Class entityClazz) {
        return hibernateTemplate.loadAll(entityClazz);
    }


The guy that handle the session for me is the HibernateTemplate from the Spring Framework. This guy that open and closes the session for me... I don´t do anything...

Why we did this? Because the responsability of handle this kind of stuff is from the DAO, not my Service or my GUI.

I shouldn´t leave my service handle Session´s stuff because if tomorrow, I need to change my DAO implementation, all my services classes must be updated too, and this isn´t a good thing!!


Top
 Profile  
 
 Post subject:
PostPosted: Wed Aug 10, 2005 8:57 am 
Expert
Expert

Joined: Thu Sep 04, 2003 8:23 am
Posts: 368
Spring wraps your service call inside a transaction and ensure that the hibernate session stay open during all the transaction.
You can then in you service method initialize all you want before the session is closed.

You can also you an opensessioninviewfilter if you want your session to be open after you exit your service method. See Spring doc for more information

_________________
Seb
(Please don't forget to give credits if you found this answer useful :)


Top
 Profile  
 
 Post subject:
PostPosted: Wed Aug 10, 2005 9:18 am 
Newbie

Joined: Fri Aug 05, 2005 7:26 am
Posts: 17
Location: Santa Barbara d´Oeste SP Brasil
scesbron wrote:
You can also you an opensessioninviewfilter if you want your session to be open after you exit your service method. See Spring doc for more information


But remember that I´m not developing using servlets, I´m using Swing, so, I can´t use the OpenSessionInViewFilter!

I need something like this, but for Swing! What can I use?


Top
 Profile  
 
 Post subject:
PostPosted: Wed Aug 10, 2005 10:01 am 
Expert
Expert

Joined: Thu Sep 04, 2003 8:23 am
Posts: 368
Sorry I forgot that,

You can find valuable post on the spring ml

http://forum.springframework.org/viewto ... +hibernate
http://forum.springframework.org/viewto ... 21c34d6d4a
http://forum.springframework.org/search ... de=results

I think the best practice is too define explicitly in your service method the level of hydratation of your objects and too have different methods for differents levels.

_________________
Seb
(Please don't forget to give credits if you found this answer useful :)


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 19 posts ]  Go to page 1, 2  Next

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.