Avatar billede fredand Forsker
05. januar 2006 - 17:04 Der er 7 kommentarer og
2 løsninger

Problems with Hibernate, the owning Session was closed

Hello!

This is probably a tricky question that I hope some one could give some hints about.

I get a strange Exception:
org.hibernate.LazyInitializationException: could not initialize proxy - the owning Session was closed

I get it at the line "customer.setsCountry(country.getName());" in this code:
package website.controller.action;

import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
import org.apache.struts.action.*;

import website.controller.form.*;
import website.model.hibernate.*;
import website.tools.*;

public class NewCustomerFormAction extends Action
{

    public ActionForward execute (ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
    {

        NewCustomerForm newCustomerForm = (NewCustomerForm) form;
          Customer customer = new Customer();
          customer.setsFName(newCustomerForm.getsFName());
          customer.setsSName(newCustomerForm.getsSName());
          customer.setsPassword(newCustomerForm.getsPassword1());
          customer.setsEmail(newCustomerForm.getsEmail());
          customer.setsAddress(newCustomerForm.getsAddress());
          customer.setsPostal(newCustomerForm.getsPostal());
          customer.setsCity(newCustomerForm.getsCity());


          Long countryId = new Long(newCustomerForm.getsCountryId());
          Country country = CountryService.getCountry(countryId);

          customer.setsCountry(country.getName());

          customer.setsPhone(newCustomerForm.getsPhone());
          customer.setnBYear(new Short(newCustomerForm.getnBYear()));
          customer.setnBMonth(new Short(newCustomerForm.getnBMonth()));
          customer.setnBDay(new Short(newCustomerForm.getnBDay()));
        customer.setsCountryId( Integer.parseInt( newCustomerForm.getsCountryId() ) );

        HttpSession session = request.getSession();
        session.setAttribute("customer", customer);

        return mapping.findForward("success");
      }
}

It looks like it has to do with Hibernate and loading classes that I do in this code:
package website.tools;

import java.util.*;

import website.tools.*;
import website.model.hibernate.*;
import org.hibernate.*;

public class CountryService
{
    public static synchronized Country getCountry(Long id)
      {
        HibernateUtil.getSessionFactory().getCurrentSession().beginTransaction();
        Session session = HibernateUtil.getSessionFactory().getCurrentSession();

        Country country = (Country) session.load(Country.class, id);
        //System.out.println( country.getName() );

        HibernateUtil.getSessionFactory().getCurrentSession().getTransaction().commit();
        HibernateUtil.getSessionFactory().close();

        return country;
    }
}

The funny thing is that if I uncomment this line:
//System.out.println( country.getName() );
It works!!!

But of course I do not want to do like that and I do not understand way. I guess Hibernate just load the parent instance, name is considered like a child or member I guess, but it is not in any relation table. The Country class looks like:
package website.model.hibernate;

public class Country
{
    private Long id;
    private String name;

    public Long getId()
    {
        return id;
    }

    private void setId(Long id)
    {
        this.id = id;
    }

      public String getName()
      {
          return  name;
      }

      public void setName(String  a)
    {
        name = a;
      }
}

The hbm.xml file looks like:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping>

    <class name="website.model.hibernate.Country" table="countries">
        <id name="id" column="id">
            <generator class="increment"/>
        </id>
            <property name="name"/>

    </class>

</hibernate-mapping>

So if any one could give some hint or if you guys could suggest a better solution then the CountryService-class. Perhaps I have done a bad design??

I hope a have describe this problem in a good way, cause I am not sure what this depends on.

Best regards
Fredrik
Avatar billede fredand Forsker
05. januar 2006 - 17:37 #1
Hello!

I solved it with the follwing deviding of the code, but I'm not satisfied with it since I now have Hibernate-code in the action-class.

So if you have a nicer design plese let me know!!!


    public ActionForward execute (ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
    {

        NewCustomerForm newCustomerForm = (NewCustomerForm) form;
          Customer customer = new Customer();
          customer.setsFName(newCustomerForm.getsFName());
          customer.setsSName(newCustomerForm.getsSName());
          customer.setsPassword(newCustomerForm.getsPassword1());
          customer.setsEmail(newCustomerForm.getsEmail());
          customer.setsAddress(newCustomerForm.getsAddress());
          customer.setsPostal(newCustomerForm.getsPostal());
          customer.setsCity(newCustomerForm.getsCity());

        HibernateUtil.getSessionFactory().getCurrentSession().beginTransaction();
        org.hibernate.Session hibernateSession = HibernateUtil.getSessionFactory().getCurrentSession();

          Long countryId = new Long(newCustomerForm.getsCountryId());
          Country country = CountryService.getCountry(hibernateSession, countryId);

          customer.setsCountry(country.getName());

        HibernateUtil.getSessionFactory().getCurrentSession().getTransaction().commit();
        HibernateUtil.getSessionFactory().close();

          customer.setsPhone(newCustomerForm.getsPhone());
          customer.setnBYear(new Short(newCustomerForm.getnBYear()));
          customer.setnBMonth(new Short(newCustomerForm.getnBMonth()));
          customer.setnBDay(new Short(newCustomerForm.getnBDay()));
        customer.setsCountryId( Integer.parseInt( newCustomerForm.getsCountryId() ) );

        HttpSession session = request.getSession();
        session.setAttribute("customer", customer);

        return mapping.findForward("success");
      }

And...

    public static synchronized Country getCountry(Session session, Long id)
      {
        //HibernateUtil.getSessionFactory().getCurrentSession().beginTransaction();
        /*Session*/ session = HibernateUtil.getSessionFactory().getCurrentSession();

        Country country = (Country) session.load(Country.class, id);
        //System.out.println( country.getName() );

        //HibernateUtil.getSessionFactory().getCurrentSession().getTransaction().commit();
        //HibernateUtil.getSessionFactory().close();

        return country;
    }

Best regards
Fredrik
Avatar billede arne_v Ekspert
05. januar 2006 - 17:42 #2
my guess (without studying the code in detail) would be that you should call HibernateUtil.getSessionFactory().getCurrentSession()
once and use the returned session in the other calls
Avatar billede fredand Forsker
05. januar 2006 - 18:07 #3
Hello!

Without being a hiberbate-expert, would you create one (1) hibernate-session for all HttpSessions/users/visitors or one for each HttpSessions/users/visitors. I guess I should be "economical" with all database connections but ofcourse also avoid bottlenecks.

To me your opinion is very valuable!

Btw do not forget to give a "svar"

Best regards
Fredrik
Avatar billede arne_v Ekspert
05. januar 2006 - 18:27 #4
one for each - definatetly - because transacations are tied to sessions I belive
Avatar billede simonvalter Praktikant
05. januar 2006 - 22:18 #5
This is a common problem. When you do country.getName() the session have already been closed. With lazy loading that will cause hibernate to try and load the value. In hibernate3 lazy loading if on by default if i remember right. Three are several solutions to this problem.
You can disable lazy loading.
You can use a fetch strategy where you initialize the values you know you need but keep everything else lazy loaded.
You can use a Servlet Filter to open the session in the view layer.
http://www.hibernate.org/43.html
You can use a hibernate interceptor from spring in the bussines layer... i would recommend this, i see no reason not to use spring when you are using hibernate.
http://www.jroller.com/page/kbaum/20040708
Avatar billede simonvalter Praktikant
05. januar 2006 - 22:41 #6
http://www.javalobby.org/java/forums/m91844921.html

As you can see in the article, it suggests doing the same thing as you do. call
country.getName() in the ContryService and explicitly initialize it. That will do if thats the only
value you will ever need.
Avatar billede fredand Forsker
28. januar 2006 - 17:16 #7
Thanks for all your help!
Please (both of you) give a svar so we could end this thread!
/Fredrik
Avatar billede arne_v Ekspert
29. januar 2006 - 00:46 #8
.
Avatar billede simonvalter Praktikant
30. januar 2006 - 11:32 #9
ok
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester

IT-JOB

Netcompany A/S

Test Consultant

Politiets Efterretningstjeneste

AI/ML udvikler i PET

IT-Universitetet i København

CIO

Politiets Efterretningstjeneste

IT Sikkerhedsarkitekt i PET