views:

2090

answers:

6

I currently mark collections in entity beans as eager to avoid getting a lazy initialization exception when I try to access the collection properties after loading the bean with the EntityManager.

If I instead leave the collection as lazy loading, how do I keep a session open? I thought about trying @Transactional, but even if that worked I wouldn't want to do it because it doesn't seem right to leave a transaction open over a long method.

+4  A: 

https://www.hibernate.org/43.html

Basically, you have a few options.

-You can use the "open session in view" pattern where you use a filter/interceptor/AOP - style logic to open a session when server side logic begins, and close it when it's through.

-You could implement conversations spanning several request-response cycles.

A plain old Servlet Filter is the easiest.

lucas
A: 

When you leave a session open that has read some data, you will leave that transaction open. Long running transactions aren't that big of a problem (although that might depend on your database) what really causes problems are locks hold for a long time, but these might only get created once you actually change data in the database. Again this depends on your database.

Jens Schauder
A: 

Now, I haven't used Spring, but I have used Hibernate in several different projects. The approach I settled on for the most recent project grew out of the Defensive Session Handling pattern (in conjunction with a servlet filter), and we are happy with it. You can find more design patterns here.

Nelson
A: 

Are you using Spring's HibernateTemplate? It will manage the session for you I believe. Alternatively if you are on Hibernate 3.0.1 or above, Spring should still be able to manage the session for you.

There is a SpringSource blog entry that describes how to set this up. I've included an extract below:

Since Hibernate 3.0.1 (and in the Java Persistence API from the moment it was first released) it became possible for Spring to manage the underlying resource without you having to go through any of the templates that are available for those technologies. This means that even if you are using the Hibernate API directly (for example through SessionFactory.getCurrentSession()), you will still be using a Spring-managed Hibernate Session. The same holds for an EntityManager obtained through a JPA EntityManagerFactory. This is another reason why you don't have to use Spring's HibernateTemplate anymore to get an integrated experience. [...]

The following is the XML that we'll use to assemble the application. As you can see, we're of course still using the Spring way of setting up Hibernate (using the LocalSessionFactoryBean).

<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
    <!– the works –>
</bean>
<bean id="accountRepo" class="com.mycompany.HibernateAccountRepository">
  <constructor-arg ref="sessionFactory"/>
</bean>

Now, as I said before, because of a small change in Hibernate 3.0.1, Spring is able to manage the Hibernate session for you, without you having to go through the Hibernate session. The one thing that was missing was the exception translation. To also get that going, you only need to annotate the repository with the @Repository annotation (provided by Spring) and turn on exception translation using a post processor.

@Repository // from org.springframework.stereotype
public class HibernateAccountRepository implements AccountRepository {
    // see above for full impl…
}
Rich Seller
The transaction boundary is the key here, not if you are using Spring's HibernateTemplate.
JamesC
+2  A: 

As others have said, you should read up on "open session in view" pattern, the basic idea of which is to have a hibernate session open for the full duration of processing http request. There are both hibernate specific and spring solutions - I used spring's before and it works fine.

In the question you mention that you don't want to have transaction open for a long time. For most of the people this is not an issue because each request is processed relatively quickly. However if in your case it is indeed impossible this pattern will not work for you. Can you elaborate on why you don't want the transactions kept open?

Gregory Mostizky
A: 

One final option which seems to of been missed is you can build your object graph based on your use-case by using a JOIN.

This will result in the object being initialized, i.e the will not be a proxy.

Use this approach if you are in control of the client (i.e you not creating open service publishing an api) because you need to know what state is being touched when the session is closed because the transaction has closed.

JamesC