-->
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.  [ 33 posts ]  Go to page 1, 2, 3  Next
Author Message
 Post subject: Question about the Open Session in View pattern
PostPosted: Mon Mar 20, 2006 8:39 pm 
Beginner
Beginner

Joined: Sun Feb 19, 2006 3:50 am
Posts: 34
I tried asking this question once but I think I might have been too verbose and people didn't want to slog through it. I'll try again and be brief.

According to http://hibernate.org/43.html#A8:
Quote:
...some developers are using a variation of this pattern that keeps the Session open until the view has been rendered, but commits the database transaction before rendering of the view. The consequences are the same as not keeping the Session open: lazy loading does not work outside of a database transaction. It doesn't matter if the Session is still open, it has no connection. Further confusion appears when this anti-pattern actually works, but simply because the auto-commit mode is actually in use.


Based on that information, I would expect the code below to throw a lazy loading exception:
Code:
Session session = HibernateUtil.getSessionFactory().getCurrentSession();

session.beginTransaction();
Person person = (Person)session.get(Person.class, new Long(1));
session.flush();
session.getTransaction().commit();

List itemList = person.getItemList();
// The next line should throw a LazyInitializationError since the property is being accessed outside of a transaction. Why does it work?
Iterator iterator = itemList.iterator();


The itemList property is a lazy-loaded property (if I debug this code the itemList is a PersistentBag whose bag property is null until after the final line executes) and I've verified that my JDBC connections are not set to auto commit. So why does the code work? Am I misunderstanding the documentation?

I'm using Hibernate 3.1.2 and I'm happy to provide any other information (logs, mapping files, etc) you might need to help me figure this out.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Mar 22, 2006 3:29 pm 
Beginner
Beginner

Joined: Sun Feb 19, 2006 3:50 am
Posts: 34
Come on, I can't be the only person to ever wonder about this. The behavior I'm seeing appears to directly violate the documentation.

If I'm a complete moron and missed something obvious, then tell me. That's fine. I just want to know what's going on.

In case it matters, I'm using MySQL 4.1.18 as the database.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Mar 22, 2006 6:09 pm 
Regular
Regular

Joined: Mon Oct 06, 2003 7:17 am
Posts: 58
Location: Switzerland
Do you use the InnoDB engine with MySQL? Because otherwise you have no transactions at all in MySQL.

Reto


Top
 Profile  
 
 Post subject: Re: Question about the Open Session in View pattern
PostPosted: Wed Mar 22, 2006 7:40 pm 
Beginner
Beginner

Joined: Mon Dec 06, 2004 4:20 pm
Posts: 34
Based on that information, I would expect the code below to throw a lazy loading exception:
Code:
Session session = HibernateUtil.getSessionFactory().getCurrentSession();

session.beginTransaction();
Person person = (Person)session.get(Person.class, new Long(1));
session.flush();
session.getTransaction().commit();

List itemList = person.getItemList();
// The next line should throw a LazyInitializationError since the property is being accessed outside of a transaction. Why does it work?
Iterator iterator = itemList.iterator();


The itemList property is a lazy-loaded property (if I debug this code the itemList is a PersistentBag whose bag property is null until after the final line executes) and I've verified that my JDBC connections are not set to auto commit. So why does the code work? Am I misunderstanding the documentation?

I'm using Hibernate 3.1.2 and I'm happy to provide any other information (logs, mapping files, etc) you might need to help me figure this out.[/quote]

The first question I would ask is, why are you loading an object in a transaction, and then committing it? This is a query - there should be no updates needed. And since the session is still open, the lazy instantiation works, because the object is still "attached" to the database.

This is a common pattern in our application, which is web-based. Objects are retrieved from the database, and the session is closed. Later on, if there is a decision to iterate over a lazy collection, we have a method that attaches the object to a session (either using session.update() or session.lock) so that iterators can be called. I believe this is what you need.

Don


Top
 Profile  
 
 Post subject:
PostPosted: Wed Mar 22, 2006 8:12 pm 
Beginner
Beginner

Joined: Sun Feb 19, 2006 3:50 am
Posts: 34
Reto wrote:
Do you use the InnoDB engine with MySQL? Because otherwise you have no transactions at all in MySQL.

Reto


Yes I am using InnoDB, so I don't think that's it. Thanks for the idea though.


Top
 Profile  
 
 Post subject: Re: Question about the Open Session in View pattern
PostPosted: Wed Mar 22, 2006 8:26 pm 
Beginner
Beginner

Joined: Sun Feb 19, 2006 3:50 am
Posts: 34
dononelson wrote:
And since the session is still open, the lazy instantiation works, because the object is still "attached" to the database.


This gets to the heart of my question so I'll address it first. According to the docs, "lazy loading does not work outside of a database transaction. It doesn't matter if the Session is still open, it has no connection." So according to the docs I should get an exception when attempting to lazy load the property outside of a transaction, even though the session is open. If the documentation is wrong, no problem. If my understanding of the documentation is wrong, again no problem. The problem is that there appears to me to be either incorrect documentation, incorrect Hibernate behavior, or pilot error, and I want to know which it is.


dononelson wrote:
The first question I would ask is, why are you loading an object in a transaction, and then committing it? This is a query - there should be no updates needed.


There are no updates, but any database interaction requires a transaction, including loading. If I don't wrap the object load in a transaction it throws "org.hibernate.HibernateException: get is not valid without active transaction" which is correct and expected behavior. This is just test code by the way, and what I'm trying to do is "simulate" an action which is properly wrapped in a transaction and retrieves an object, and then does a "JSP render" which is not wrapped in a transaction and should thus throw an exception when it tries to lazy load a property.

Thank you for your ideas. I appreciate that you at least bothered to respond, but I don't think my question is answered yet. According to the documentation, the sample code should throw an exception since I'm accessing a lazy-loaded property outside of a transaction. Why isn't an exception being thrown?


Top
 Profile  
 
 Post subject:
PostPosted: Wed May 10, 2006 4:13 pm 
Newbie

Joined: Fri Apr 21, 2006 10:49 am
Posts: 18
ninjapower I read this thread before, at the time did not make too much sense, but now I am looking for the same kind of problems that you have faced.

I had the same code that you posted while testing the lazy initialization and I do get the expected exception throwLazyInitializationException(AbstractPersistentCollection.java:358)

Here it is my code which is pretty much the same as yours
Code:
        // Open transaction
        Session session = HibernateUtil.getSessionFactory().getCurrentSession();
        session.beginTransaction();

        // Get Employee
        DAOFactory objDAOFactory = DAOFactory
                .getDAOFactory(Constants.HIBERNATE_DAO_FACTORY);
        EmployeeDAO objEmployeeDAO = objDAOFactory.getEmployeeDAO();
        Employee objEmployee;
        objEmployee = objEmployeeDAO.getById(new Integer(0));
        System.out.println("The employee id is " + objEmployee.getId());
        // flush and commit transaction
        session.flush();
        session.getTransaction().commit();
       
        // Get addresses.
        Address objAddress;
        Set setAddresses = objEmployee.getAddresses();
        Iterator i = setAddresses.iterator();
        while (i.hasNext())
        {
            objAddress = (Address) i.next();
            System.out.println("The address is: " + objAddress.getValue());
        }


I would like to know how come is yours not throwing the exception. Have you found a reasoning?


Top
 Profile  
 
 Post subject:
PostPosted: Wed May 10, 2006 4:45 pm 
Hibernate Team
Hibernate Team

Joined: Mon Aug 25, 2003 9:11 pm
Posts: 4592
Location: Switzerland
Of course you can access an unitialized placeholder/proxy/whatever outside of a transaction if the Session is still open. The Session then gets a database connection just for that, and hopefully you enabled auto-commit in your Hibernate configuration, then you will get an auto-committed connection. Otherwise you get "undefined" stuff.

The reason why getCurrentSession().load() (for example) has to throw an exception, if you didn't call getCurrentSession().beginTransaction() before, is that otherwise we can't force you to do a commit() or rollback(), which ultimately closes the Session and cleans up the thread-local.

The real question is why you guys even want to use stuff that has no benefits at all (auto commit behavior) and that you don't fully understand. Just use regular transaction demarcation if you access the Session.


Top
 Profile  
 
 Post subject:
PostPosted: Wed May 10, 2006 4:57 pm 
Expert
Expert

Joined: Tue Apr 25, 2006 12:04 pm
Posts: 260
Code:
// Open transaction
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
session.beginTransaction();

// Get Employee
DAOFactory objDAOFactory = DAOFactory
   .getDAOFactory(Constants.HIBERNATE_DAO_FACTORY);
EmployeeDAO objEmployeeDAO = objDAOFactory.getEmployeeDAO();
Employee objEmployee;
objEmployee = objEmployeeDAO.getById(new Integer(0));
System.out.println("The employee id is " + objEmployee.getId());

// you can force initialization of proxies
if ( !Hibernate.isInitialized( objEmployee.getAddresses() ) ) {
   Hibernate.initialize( objEmployee.getAddresses() );
}

// flush and commit transaction
session.flush();
session.getTransaction().commit();

// Get addresses.
Address objAddress;
Set setAddresses = objEmployee.getAddresses();
Iterator i = setAddresses.iterator();
while (i.hasNext())
{
    objAddress = (Address) i.next();
    System.out.println("The address is: " + objAddress.getValue());
}


I suppose you want to use address collection information somewhere in your UI. To remove LazyInit...Exception, you can force Hibernate to initalize the proxies in the collection by calling Hibernate.initialize( collection ).


Top
 Profile  
 
 Post subject:
PostPosted: Wed May 10, 2006 4:59 pm 
Beginner
Beginner

Joined: Sun Feb 19, 2006 3:50 am
Posts: 34
I am absolutely not using auto commit. And yet I can still successfully access a not-yet-lazy-loaded property outside of a transaction. According to the docs, this should not be possible: "lazy loading does not work outside of a database transaction". That's pretty explicit, but it's not what I'm seeing.

I understand transactions fine. I use them. I do not want to have my app use auto commit behavior. I have auto commit turned off at my tomcat data source and in the hibernate properties. But I'm seeing behavior in hibernate that doesn't match the very explicit documentation stating "lazy loading does not work outside of a database transaction" even though auto commit is off.

I would be happy to create a junit (with hibernate properties, mapping files, etc) to prove this if you want.


Top
 Profile  
 
 Post subject:
PostPosted: Wed May 10, 2006 5:08 pm 
Beginner
Beginner

Joined: Sun Feb 19, 2006 3:50 am
Posts: 34
Quote:
I suppose you want to use address collection information somewhere in your UI. To remove LazyInit...Exception, you can force Hibernate to initalize the proxies in the collection by calling Hibernate.initialize( collection ).


No. No no no no no. I've been very patient, but for the love of pete, why is my question so hard to understand? The hibernate docs state very explicitly "lazy loading does not work outside of a database transaction [even if you access the property in the same session you used to load the object]". I have code that proves this wrong. It's very simple and I'll make a junit and post it up here to prove it. Lazy loading appears to work just fine outside of a transaction even if I have auto commit turned off!.

This seems to show that either the hibernate docs are incorrect, or there's a bug in the hibernate behavior. Which is it?

I do not have a problem I can't solve. I've already solved the Open Session in View pattern for my app, and it works great (and yes, everything is surrounded by transactions.) I am not one of those people that thinks "well, if it works then I'm not going to worry about it." That leads to nasty hard to solve bugs in the future. So the reason I'm making this post is because the documentation and hibernate behavior are inconsistent, and I want to understand why, NOT because I have a problem I need help solving!


Last edited by ninjapowered on Wed May 10, 2006 5:19 pm, edited 1 time in total.

Top
 Profile  
 
 Post subject:
PostPosted: Wed May 10, 2006 5:17 pm 
Expert
Expert

Joined: Tue Apr 25, 2006 12:04 pm
Posts: 260
http://www.hibernate.org/hib_docs/v3/re ... ching-lazy

Section 19.1.1 ( linked above ) states exception occurs outside session and not transaction. I had verified before posting my last post.


Top
 Profile  
 
 Post subject:
PostPosted: Wed May 10, 2006 5:29 pm 
Beginner
Beginner

Joined: Sun Feb 19, 2006 3:50 am
Posts: 34
bkmr_77 wrote:
http://www.hibernate.org/hib_docs/v3/reference/en/html_single/#performance-fetching-lazy

Section 19.1.1 ( linked above ) states exception occurs outside session and not transaction. I had verified before posting my last post.


Thank you! This is helpful. Now go read http://hibernate.org/43.html#A8. It states in no uncertain terms almost the exact opposite. The relevant portion is: "Apparently, though never promoted in Hibernate documentation, some developers are using a variation of this pattern that keeps the Session open until the view has been rendered, but commits the database transaction before rendering of the view. The consequences are the same as not keeping the Session open: lazy loading does not work outside of a database transaction. It doesn't matter if the Session is still open, it has no connection. Further confusion appears when this anti-pattern actually works, but simply because the auto-commit mode is actually in use."

I have auto commit mode turned off in the hibernate properties, and in my data source. According to http://hibernate.org/43.html#A8 it shouldn't work, but it does. http://www.hibernate.org/hib_docs/v3/reference/en/html_single/#performance-fetching-lazy seems to indicate that it would work, but it's not nearly as explicit as http://hibernate.org/43.html#A8. So....what's going on? Is http://hibernate.org/43.html#A8 incorrect?


Top
 Profile  
 
 Post subject:
PostPosted: Wed May 10, 2006 5:29 pm 
Hibernate Team
Hibernate Team

Joined: Mon Aug 25, 2003 9:11 pm
Posts: 4592
Location: Switzerland
What part of "if auto-commit is turned off, behavior is undefined" is hard to understand?


Top
 Profile  
 
 Post subject:
PostPosted: Wed May 10, 2006 5:30 pm 
Hibernate Team
Hibernate Team

Joined: Mon Aug 25, 2003 9:11 pm
Posts: 4592
Location: Switzerland
I've updated the page, by the way. But as long as you think you absolutetly have to define something that is completely random, depending on various other external factors, you still won't be happy.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 33 posts ]  Go to page 1, 2, 3  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.