[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