[PJUG Javamail] Problem with hibernate

Sean Adkinson sean.adkinson at gmail.com
Fri Sep 18 14:51:15 EDT 2009


Michael,

Glad you fixed the issue.  You should know, though, that get() doesn't
return a proxy object, which is why you wouldn't get the
LazyInitializationException.  Therefore if you have a large intertwined
database and object structure, getting (as opposed to loading) a single
object could result in many database calls and extremely slow performance,
since it gets everything all at once.

The situation at my current job before I came on board was the application
would get a Student from the database.  Since nothing was lazy-loaded,
getting a Student resulted in getting all their Enrollments, all their
Courses, all their Teachers, and almost everything in the database!
Lazy-loading can be advantageous if you usually don't want everything at
once.  Rather, the proxy only goes and initializes the lazy association when
asked.

The "asking" can happen in a JSF (or JSP in our case), when you write
something like ${student.enrollments}, which calls getEnrollments() on
Student.  Since the Student is a proxy and the enrollments collection is
lazy-loaded, calling that getter results in a database call to initialize
the collection, and if there is no current session, you get the
LazyInitializationException.

So if your User class doesn't have a very large assocation tree, "getting"
should be fine, but just make sure you understand the consequences if the
application and database get larger.

Glad I could help!

- Sean




On Fri, Sep 18, 2009 at 11:34 AM, Michael Phoenix <
michaelandrewphoenix at gmail.com> wrote:

> Sean,
>
> Thanks so much for your kind response. Even though I managed to
> resolve the problem through a much simpler change, your response is a
> good teaching moment as I continue to learn all the ins and outs of
> hibernate and JSF.
> I managed to resolve the problem by changing the load method in my DAO
> to a get method. I was thinking about making that change anyway as get
> does not throw exceptions if you don';t find the object matching the
> identifier. It was quite a surprise to find that using load was the
> source of my problem. I am definitely not initializing the proxy from
> the JSF. All hibernate processing is taking place in the DAO in order
> to separate the data access from the Web app logic. From what you are
> telling me you need to do to get hibernate to work from a Web app, I
> think that is a good strategy.
>
> On Fri, Sep 18, 2009 at 12:39 PM, Sean Adkinson <sean.adkinson at gmail.com>
> wrote:
> > Hi Michael,
> >
> > That error doesn't necessarily mean that there isn't a session, it just
> > means that there isn't a session associated with that HibernateProxy
> object
> > (in your case, the User).  This can happen if you hold a lazy-loaded
> object
> > around after a transaction is committed or the session is closed.
> >
> > For example, let's say that Person objects have a lazy loaded Emails
> > association.
> >
> > session.beginTransaction();
> > Person p = dao.getPerson();
> > session.commitTransaction();
> > p.getEmails();  <--- lazy initialization fail
> >
> > Now I don't see exactly how this is happening given your code below, but
> you
> > say it is happening in your JSF page.  Sometimes transactions are
> committed
> > after Actions run, before beginning to parse the JSF, so if that is the
> > case, trying to initialize the proxy from the JSF would cause this error.
> >
> > A few ways we solved this problem:
> >
> > 1) Configure sessions with hibernate to have long conversations, so that
> the
> > session isn't flushed on transaction commit.  You can do this by using a
> > custom extension of ThreadLocalSessionContext that only flushes manually,
> > and setting it as the hibernate.current_session_context_class property.
> > Note that this will mean that you need to control the session flushing on
> > your own, and should flush after all processing is done.
> >
> > 2) Have an open transaction around JSF processing.  Maybe use a
> > ServletFilter that starts and stops transactions/sessions between entire
> > requests.
> >
> > 3) Given a "detached" object (one that has no session associated with it
> and
> > will throw a LazyInitializatioException if a lazy-loaded property is
> > accessed), "reattach" the object to the current session.  In our
> > HibernateUtil, we have the following method:
> >
> >     public void attachObjectToCurrentSession(Object object)
> >     {
> >         getSession().lock(object, LockMode.NONE);
> >     }
> >
> >
> > Let me know if any of this helps!
> >
> > - Sean
> >
> >
> >
> > On Fri, Sep 18, 2009 at 10:19 AM, Michael Phoenix
> > <michaelandrewphoenix at gmail.com> wrote:
> >>
> >> I'm having a problem with lazy fetching and accessing data through
> >> hibernate from my JSF Web app. I am using a DAO pattern to access my
> >> data through Hibernate. At first, it woriked fine and would pass all
> >> my unit tests. When I tried to access it though my Web bean LogonBean,
> >> it does not return any data into the User object I initialize, but
> >> doesn't give me any data. I have double-checked the mysql database
> >> table and the record with the key I am using is definitely there. When
> >> I ran junit tests again, I started getting this exception in the find
> >> method:
> >>
> >> Code:
> >> org.hibernate.LazyInitializationException <init>
> >> SEVERE: could not initialize proxy - no Session
> >>
> >>
> >> I cannot understand why it cannot find the session as the session is
> >> being created just before the load. I did a debug on it and it appears
> >> the session is there when the load is executed. The other DAO methods
> >> run fine. There is a lot written on lazy fetching and mixed reviews on
> >> turning it off. I'm not sure I can even do that in this simple
> >> database. Suggestions on what the problem might be and how to resolve
> >> it would be greatly appreciated.
> >>
> >> I'm using Hibernate 3, MySQL 5.0, and NetBeans 6.7.1
> >>
> >> hibernate-cfg.xml
> >> Code:
> >> <?xml version="1.0" encoding="UTF-8"?>
> >> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate
> >> Configuration DTD 3.0//EN"
> >> "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
> >> <hibernate-configuration>
> >>  <session-factory>
> >>    <property
> >> name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
> >>    <property
> >>
> name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
> >>    <property
> >>
> name="hibernate.connection.url">jdbc:mysql://localhost:3306/quoteestimator</property>
> >>    <property name="hibernate.connection.username">root</property>
> >>    <property name="hibernate.connection.password">dilbert</property>
> >>    <mapping resource="user.hbm.xml"/>
> >>  </session-factory>
> >> </hibernate-configuration>
> >>
> >>
> >> user.hbm.xml
> >> Code:
> >> <?xml version="1.0" encoding="UTF-8"?>
> >> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD
> >> 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
> >>
> >> <hibernate-mapping>
> >>  <class name="com.lingosys.hibernate.quoteest.User" table="users">
> >>    <id name="id" type="string">
> >>        <generator class="assigned"/>
> >>    </id>
> >>    <property name="name" type="string"/>
> >>    <property name="password" type="string"/>
> >>    <property name="admin" type="char"/>
> >>  </class>
> >> </hibernate-mapping>
> >>
> >>
> >> UserDao.java
> >> Code:
> >> /*
> >> * To change this template, choose Tools | Templates
> >> * and open the template in the editor.
> >> */
> >>
> >> package com.lingosys.hibernate.quoteest;
> >>
> >> /**
> >> *
> >> * @author mphoenix
> >> */
> >> import org.hibernate.HibernateException;
> >> import org.hibernate.Session;
> >> import org.hibernate.Transaction;
> >> import org.hibernate.Query;
> >> import java.util.List;
> >>
> >> /**
> >> * The Data Access Object for managing the persistent Users.
> >> *
> >> */
> >> public class UserDao {
> >>    private Session session;
> >>    private Transaction tx;
> >>
> >>    public UserDao() {
> >>        HibernateFactory.buildIfNeeded();
> >>    }
> >>
> >>    /**
> >>     * Insert a new User into the database.
> >>     * @param User
> >>     */
> >>    public void create(User User) throws DAOException {
> >>        try {
> >>            startOperation();
> >>            session.save(User);
> >>            tx.commit();
> >>        } catch (HibernateException e) {
> >>            handleException(e);
> >>        } finally {
> >>            HibernateFactory.close(session);
> >>        }
> >>    }
> >>
> >>
> >>    /**
> >>     * Delete a detached User from the database.
> >>     * @param user
> >>     */
> >>    public void delete(User user) throws DAOException {
> >>        try {
> >>            startOperation();
> >>            session.delete(user);
> >>            tx.commit();
> >>        } catch (HibernateException e) {
> >>            handleException(e);
> >>        } finally {
> >>            HibernateFactory.close(session);
> >>        }
> >>    }
> >>    /**
> >>     * Find an User by its primary key.
> >>     * @param id
> >>     * @return
> >>     */
> >>    public User find(String id) throws DAOException {
> >>        User user = null;
> >>        try {
> >>            startOperation();
> >>            user = (User) session.load(User.class, id);
> >>            tx.commit();
> >>        } catch (HibernateException e) {
> >>            handleException(e);
> >>        } finally {
> >>            HibernateFactory.close(session);
> >>        }
> >>        return user;
> >>    }
> >>
> >>    /**
> >>     * Updates the state of a detached User.
> >>     *
> >>     * @param User
> >>     */
> >>    public void update(User User) throws DAOException {
> >>        try {
> >>            startOperation();
> >>            session.update(User);
> >>            tx.commit();
> >>        } catch (HibernateException e) {
> >>            handleException(e);
> >>        } finally {
> >>            HibernateFactory.close(session);
> >>        }
> >>    }
> >>
> >>    /**
> >>     * Finds all Users in the database.
> >>     * @return
> >>     */
> >>    public List findAll() throws DAOException{
> >>        List users = null;
> >>        try {
> >>            startOperation();
> >>            Query query = session.createQuery("from User");
> >>            users =  query.list();
> >>            tx.commit();
> >>        } catch (HibernateException e) {
> >>            handleException(e);
> >>        } finally {
> >>            HibernateFactory.close(session);
> >>        }
> >>        return users;
> >>    }
> >>
> >>    private void handleException(HibernateException e) throws
> DAOException
> >> {
> >>        HibernateFactory.rollback(tx);
> >>        throw new DAOException(e);
> >>    }
> >>
> >>    private void startOperation() throws HibernateException {
> >>        session = HibernateFactory.openSession();
> >>        tx = session.beginTransaction();
> >>    }
> >>
> >> }
> >>
> >>
> >> HibernateFactory.java
> >> Code:
> >> package com.lingosys.hibernate.quoteest;
> >>
> >> import org.hibernate.*;
> >> import org.hibernate.cfg.Configuration;
> >>
> >> public class HibernateFactory {
> >>    private static SessionFactory sessionFactory;
> >>
> >>    /**
> >>     * Constructs a new Singleton SessionFactory
> >>     * @return
> >>     * @throws HibernateException
> >>     */
> >>    public static SessionFactory buildSessionFactory() throws
> >> HibernateException {
> >>        if (sessionFactory != null) {
> >>            closeFactory();
> >>        }
> >>        return configureSessionFactory();
> >>    }
> >>
> >>    /**
> >>     * Builds a SessionFactory, if it hasn't been already.
> >>     */
> >>    public static SessionFactory buildIfNeeded() throws DAOException{
> >>        if (sessionFactory != null) {
> >>            return sessionFactory;
> >>        }
> >>        try {
> >>            return configureSessionFactory();
> >>        } catch (HibernateException e) {
> >>            throw new DAOException(e);
> >>        }
> >>    }
> >>    public static SessionFactory getSessionFactory() {
> >>        return sessionFactory;
> >>    }
> >>
> >>
> >>    public static Session openSession() throws HibernateException {
> >>        buildIfNeeded();
> >>        return sessionFactory.openSession();
> >>    }
> >>
> >>    public static void closeFactory() {
> >>        if (sessionFactory != null) {
> >>            try {
> >>                sessionFactory.close();
> >>            } catch (HibernateException ignored) {
> >>                System.out.println("Couldn't close SessionFactory" +
> >> ignored);
> >>            }
> >>        }
> >>    }
> >>
> >>    public static void close(Session session) {
> >>        if (session != null) {
> >>            try {
> >>                session.close();
> >>            } catch (HibernateException ignored) {
> >>                System.out.println("Couldn't close Session" + ignored);
> >>            }
> >>        }
> >>    }
> >>
> >>    public static void rollback(Transaction tx) {
> >>        try {
> >>            if (tx != null) {
> >>                tx.rollback();
> >>            }
> >>        } catch (HibernateException ignored) {
> >>            System.out.println("Couldn't rollback Transaction" +
> ignored);
> >>        }
> >>    }
> >>    /**
> >>     *
> >>     * @return
> >>     * @throws HibernateException
> >>     */
> >>    private static SessionFactory configureSessionFactory() throws
> >> HibernateException {
> >>        Configuration configuration = new Configuration();
> >>        configuration.configure();
> >>        sessionFactory = configuration.buildSessionFactory();
> >>        return sessionFactory;
> >>    }
> >> }
> >>
> >>
> >> LogonBean.java (authenticate method only)
> >> Code:
> >>    public String authenticate() throws NoSuchAlgorithmException,
> >> NoSuchAlgorithmException, UnsupportedEncodingException {
> >>        UserDao dao = new UserDao();
> >>        String id = getUid();
> >>        User user = dao.find(id);
> >>        PasswordProcessor pp = PasswordProcessor.getInstance();
> >>        if (pp.encrypt(getPassword()).equals(user.getPassword())) {
> >>            setAuthenticated(true);
> >>            if (user.getAdmin() == 'Y')
> >>                setAdmin(true);
> >>            return "loggedon";
> >>        }
> >>        else {
> >> //            FacesContext.getCurrentInstance().
> >> //                    addMessage(null, new FacesMessage("Incorrect
> >> user ID and/or password, please try again."));
> >>            return "failed";
> >>        }
> >>
> >>    }
> >>
> >>
> >> Junit test code
> >> Code:
> >>    @Test
> >>    public void testCreate() {
> >>        System.out.println("create");
> >>        User user = new User("testing", "Phoenix, Michael", "pass", 'Y');
> >>        UserDao instance = new UserDao();
> >>        instance.create(user);
> >>    }
> >>
> >>    @Test
> >>    public void testFind() {
> >>        System.out.println("find");
> >>        String id = "testing";
> >>        UserDao instance = new UserDao();
> >>        User result = instance.find(id);
> >>        System.out.println("name = " + result.getName());
> >>        System.out.println("password = " + result.getPassword());
> >>    }
> >>
> >>    @Test
> >>    public void testUpdate() {
> >>        System.out.println("update");
> >>        User User = new User("testing", "Phoenix, M", "nopass", 'Y');
> >>        UserDao instance = new UserDao();
> >>        instance.update(User);
> >>    }
> >>
> >>    @Test
> >>    public void testFindAll() {
> >>        System.out.println("findAll");
> >>        UserDao instance = new UserDao();
> >>        List result = instance.findAll();
> >>        Iterator iter = result.iterator();
> >>        while (iter.hasNext()) {
> >>            User user = (User) iter.next();
> >>            System.out.println("name = " + user.getName());
> >>            System.out.println("password = " + user.getPassword());
> >>        }
> >>    }
> >>
> >>    @Test
> >>    public void testDelete() {
> >>        System.out.println("delete");
> >>        User user = new User("testing", "Phoenix, M", "nopass", 'Y');
> >>        UserDao instance = new UserDao();
> >>        instance.delete(user);
> >>    }
> >> _______________________________________________
> >> Web Site - http://www.pjug.org/
> >> Javamail mailing list
> >> Javamail at pjug.org
> >> http://www.pjug.org/mailman/listinfo/javamail
> >
> >
> >
> > --
> > Sean Adkinson
> > (503) 731-5488 work, (503) 866-0852 cell
> > sean.adkinson at gmail.com
> >
>



-- 
Sean Adkinson
(503) 731-5488 work, (503) 866-0852 cell
sean.adkinson at gmail.com
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://www.pjug.org/pipermail/javamail/attachments/20090918/a989f25e/attachment.html 


More information about the Javamail mailing list