-->
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.  [ 6 posts ] 
Author Message
 Post subject: tx.rollback() and session.close() failing
PostPosted: Mon Aug 30, 2004 4:16 pm 
Beginner
Beginner

Joined: Sat Dec 20, 2003 5:09 pm
Posts: 38
Problem

I'm using the threadlocal pattern to manage the hibernate session in a stand-alone, command line, XML parser. In testing, I found that my transaction rollback/session close (located in the finally block) is failing when I try to insert a row into the database where the hibernate not null propety is set to true. When this happens, the database quickly runs out of connections - things get ugly real fast. Of course, I've updated the parser to deal with missing fields that correspond to not-null columns. However, the fact that tx.rollback() and session.close() fail has me a little concerned.

Anyone see anything obvious? Thoughts are greatly appreciated.

Thanks,

Rich

Hibernate version:

Code:
version 2.1.4, 02. June 2004


Mapping documents:

Code:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration
    PUBLIC "-//Hibernate/Hibernate Configuration DTD//EN"
    "http://hibernate.sourceforge.net/hibernate-configuration-2.0.dtd">

<hibernate-configuration>

   <session-factory >

        <property name="connection.driver_class">org.postgresql.Driver</property>
        <property name="connection.url">jdbc:postgresql://test.domain.com/test</property>
        <property name="connection.username">test</property>
        <property name="connection.password">test</property>
        <property name="show_sql">false</property>
        <property name="dialect">net.sf.hibernate.dialect.PostgreSQLDialect</property>
        <property name="c3p0.acquire_increment">1</property>
        <property name="c3p0.idle_test_period">100</property> <!-- seconds -->
        <property name="c3p0.max_size">100</property>
        <property name="c3p0.max_statements">0</property>
        <property name="c3p0.min_size">10</property>
        <property name="c3p0.timeout">100</property> <!-- seconds -->

        <!-- Mapping files -->
        <mapping resource="persistence/hibernate/Employee.hbm.xml"/>

    </session-factory>

</hibernate-configuration>

Code:
<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE hibernate-mapping PUBLIC '-//Hibernate/Hibernate Mapping DTD 2.0//EN'
                                   'http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd'>


<hibernate-mapping>

    <class name = "persistence.hibernate.Employee" table="employees">
        <meta attribute="class-description">
        Class used by Hibernate to abstract the mavmail.employees table.
       
        !!NOTE!! This class is autogenerated by hibernate during the build
                 process. Any edits to the classfile will be lost!
                             
        @author  $Author: rgara $
        @version $Revision: 1.1 $
        @since $Date: 2004/07/23 16:02:53 $
        </meta>
       
        <id name="id" type="int" column="id" unsaved-value="0">
            <meta attribute="scope-set">protected</meta>
            <meta attribute="field-description">employees primary key</meta>
            <generator class="sequence">
                <param name="sequence">mmseq</param>
            </generator>
        </id>

        <property name="cid" column="cid" type="integer" not-null="true">
            <meta attribute="field-description">The client ID.</meta>
        </property>

        <property name="con_contactid" column="crm_emp_id" type="integer">
            <meta attribute="field-description">@utoCRM employee ID</meta>
        </property>
           
        <property name="con_status" column="active" type="boolean">
            <meta attribute="field-description">Employees active status. 9=inactive, 0=active</meta>
        </property> 
       
        <property name="con_firstname" column="fname" type="string" not-null="true">
            <meta attribute="field-description">The employees first name.</meta>
        </property>

        <property name="con_lastname" column="lname" type="string" not-null="true">
            <meta attribute="field-description">The employees last name.</meta>
        </property>       

        <property name="mname" column="mname" type="string" not-null="true">
            <meta attribute="field-description">The employees middle name.</meta>
        </property>   
        <property name="con_title" column="comment" type="string">
            <meta attribute="field-description">The employees desired title.</meta>
        </property> 

        <property name="con_email" column="email" type="string" not-null="true">
            <meta attribute="field-description">The employees email address.</meta>
        </property> 
           
        <property name="priv" column="priv" type="integer" not-null="true">
            <meta attribute="field-description">The employee privaledge level. @utoCRM employees should have the lowest priv of 1</meta>
        </property> 
       
        <property name="title" column="title" type="integer" not-null="true">
            <meta attribute="field-description">The employee title. Indexes into dynamicselectlistitems table</meta>
        </property> 
       
    </class>

        <query name="persistance.hibernate.findByClientAndEmployeeID">
        <![CDATA[
            from persistence.hibernate.Employee As E where
            E.cid = :CID and E.con_contactid = :EID
        ]]>
    </query>
   
</hibernate-mapping>


Code between sessionFactory.openSession() and session.close():


Code:

package persistence.hibernate;

/******************************************************************************
* Utility class for managing the Hibernate session
*
* @author  $Author: rgara $
* @version $Revision: 1.2 $
* @since $Date: 2004/08/19 19:11:34 $
*****************************************************************************/

import java.util.Map;
import java.util.HashMap;

import javax.naming.InitialContext;
import javax.naming.NamingException;

import net.sf.hibernate.Session;
import net.sf.hibernate.Transaction;
import net.sf.hibernate.SessionFactory;
import net.sf.hibernate.cfg.Configuration;
import net.sf.hibernate.HibernateException;


import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.beanutils.BeanUtils;

public class HibernateUtils
{
   //==========================================================================
   //                        P U B L I C   M E T H O D S
   //==========================================================================

   /***************************************************************************
    * Returns a Hibernate session for the current thread
    *
    * @return The Hibernate session object.
    * @throws NamingException
    * @throws HibernateException
    **************************************************************************/
    public static Session getSession()
        throws NamingException, HibernateException
    {
        boolean debug = _log.isDebugEnabled();
       
        Session s = (Session) session.get();
        if (s == null)
        {
            if(debug) { _log.debug("Acquiring new session factory"); }
         
            // This will look for the default hibernate config file
            SessionFactory sf = new Configuration().configure().buildSessionFactory();
         
            s = sf.openSession();
            session.set(s);
           
            if(debug) { _log.debug("Session factory acquired"); }
        }
        else
        {
            if(debug) { _log.debug("Session acquired from thread local"); }
        }
       
        return s;
    }

   /***************************************************************************
    * Closes the Hibernate session for the current thread
    *
    * @throws HibernateException
    **************************************************************************/
    public static void closeSession()
       throws HibernateException
   {
       Session s = (Session) session.get();
       session.set(null);

       if (s != null)
       {
          s.flush();
          s.close();

          if(_log.isDebugEnabled())
          {
             _log.debug("Closing session");
          }
       }
       else
       {
          if(_log.isDebugEnabled())
          {
             _log.debug("S was null, not calling close()");
          }
       }
    }
   
   /***************************************************************************
    * Attempts to persist a Hibernate bean to it's corresponding database table
    * @param bean - Hibernate bean to persist
    * @return true if successful, false on errors
    **************************************************************************/
    public static boolean persistHibernateBean(Object bean)
    {
        Transaction  tx        = null;
        boolean      noErrors  = true;

        if(bean == null)
        {
            _log.error("Attempting to presist a null List! Action skipped");
        }
        else
        {
           try
           {
               Session sess = getSession();

               tx = sess.beginTransaction();

               sess.saveOrUpdate(bean);

               tx.commit();
           }
           catch(NamingException ne)
           {
               _log.error("NamingException: ", ne);
               
               noErrors = false;
           }
           catch(HibernateException he)
           {
               _log.error("Hibernate Exception: ", he);

               noErrors = false;
           }
           catch(Exception e)
           {
               _log.error("Unknown error: ", e);

               noErrors = false;
           } 
           finally
           {
               try
               {
//                 Check for rollbacks
                   if( (noErrors == false) && (tx != null))
                   {
                       tx.rollback();
                       closeSession();
                   }
               }
               catch (HibernateException he)
               {
                   _log.error("Failed to rollback/close session: ", he);
               }
               catch(Exception e)
               {
                   _log.error("Failed to rollback/close session: ", e);
               } 
           }
           
        } // End if List is null

        return noErrors;
    }
   
   //==========================================================================
   //                           P R I V A T E   D A T A
   //==========================================================================

   /***************************************************************************
    * Thread local class used to store/retrieve the hibernate session
    **************************************************************************/
    private static final ThreadLocal session = new ThreadLocal();

   /***************************************************************************
    * This logger
    **************************************************************************/
    private static Log _log = LogFactory.getLog
       (persistence.hibernate.HibernateUtils.class);
}


Full stack trace of any exception that occurs:

Code:
2004-08-19 16:12:55,749 ERROR [main] (HibernateUtils.java:135) - Hibernate Exception:
net.sf.hibernate.PropertyValueException: not-null property references a null or transient value: persistence.hibernate.Employee.con_email
   at net.sf.hibernate.impl.SessionImpl.checkNullability(SessionImpl.java:1276)
   at net.sf.hibernate.impl.SessionImpl.doSave(SessionImpl.java:928)
   at net.sf.hibernate.impl.SessionImpl.doSave(SessionImpl.java:857)
   at net.sf.hibernate.impl.SessionImpl.saveWithGeneratedIdentifier(SessionImpl.java:779)
   at net.sf.hibernate.impl.SessionImpl.save(SessionImpl.java:738)
   at net.sf.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:1387)
   at persistence.hibernate.HibernateUtils.persistHibernateBean(HibernateUtils.java:123)
   at persistence.EmployeeDAO.create(EmployeeDAO.java:53)
   at xml.CrmCaddyXMLParser.saveEmployee(CrmCaddyXMLParser.java:455)
   at xml.CrmCaddyXMLParser.endElement(CrmCaddyXMLParser.java:180)
   at org.apache.xerces.parsers.AbstractSAXParser.endElement(Unknown Source)
   at org.apache.xerces.impl.dtd.XMLDTDValidator.endNamespaceScope(Unknown Source)
   at org.apache.xerces.impl.dtd.XMLDTDValidator.handleEndElement(Unknown Source)
   at org.apache.xerces.impl.dtd.XMLDTDValidator.endElement(Unknown Source)
   at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanEndElement(Unknown Source)
   at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl$FragmentContentDispatcher.dispatch(Unknown Source)
   at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source)
   at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
   at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
   at org.apache.xerces.parsers.XMLParser.parse(Unknown Source)
   at org.apache.xerces.parsers.AbstractSAXParser.parse(Unknown Source)
   at xml.CRMCaddy.main(CRMCaddy.java:131)
2004-08-19 16:12:55,839 ERROR [main] (HibernateUtils.java:158) - Failed to rollback/close session:
net.sf.hibernate.PropertyValueException: not-null property references a null or transient value: persistence.hibernate.Employee.con_email
   at net.sf.hibernate.impl.SessionImpl.checkNullability(SessionImpl.java:1276)
   at net.sf.hibernate.impl.SessionImpl.flushEntity(SessionImpl.java:2567)
   at net.sf.hibernate.impl.SessionImpl.flushEntities(SessionImpl.java:2454)
   at net.sf.hibernate.impl.SessionImpl.flushEverything(SessionImpl.java:2256)
   at net.sf.hibernate.impl.SessionImpl.flush(SessionImpl.java:2235)
   at persistence.hibernate.HibernateUtils.closeSession(HibernateUtils.java:84)
   at persistence.hibernate.HibernateUtils.persistHibernateBean(HibernateUtils.java:153)
   at persistence.EmployeeDAO.create(EmployeeDAO.java:53)
   at xml.CrmCaddyXMLParser.saveEmployee(CrmCaddyXMLParser.java:455)
   at xml.CrmCaddyXMLParser.endElement(CrmCaddyXMLParser.java:180)
   at org.apache.xerces.parsers.AbstractSAXParser.endElement(Unknown Source)
   at org.apache.xerces.impl.dtd.XMLDTDValidator.endNamespaceScope(Unknown Source)
   at org.apache.xerces.impl.dtd.XMLDTDValidator.handleEndElement(Unknown Source)
   at org.apache.xerces.impl.dtd.XMLDTDValidator.endElement(Unknown Source)
   at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanEndElement(Unknown Source)
   at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl$FragmentContentDispatcher.dispatch(Unknown Source)
   at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source)
   at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
   at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
   at org.apache.xerces.parsers.XMLParser.parse(Unknown Source)
   at org.apache.xerces.parsers.AbstractSAXParser.parse(Unknown Source)
   at xml.CRMCaddy.main(CRMCaddy.java:131)


Name and version of the database you are using:

Code:
postgresql 7.2.3


Debug level Hibernate log excerpt:

Code:
15:46:55,324 DEBUG SessionImpl:825 - saving [persistence.hibernate.Employee#13498699]
15:46:55,334 ERROR HibernateUtils:135 - Hibernate Exception:
net.sf.hibernate.PropertyValueException: not-null property references a null or transient value: persistence.hibernate.Employee.con_lastname
        at net.sf.hibernate.impl.SessionImpl.checkNullability(SessionImpl.java:1276)
        at net.sf.hibernate.impl.SessionImpl.doSave(SessionImpl.java:928)
        at net.sf.hibernate.impl.SessionImpl.doSave(SessionImpl.java:857)
        at net.sf.hibernate.impl.SessionImpl.saveWithGeneratedIdentifier(SessionImpl.java:779)
        at net.sf.hibernate.impl.SessionImpl.save(SessionImpl.java:738)
        at net.sf.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:1387)
        at persistence.hibernate.HibernateUtils.persistHibernateBean(HibernateUtils.java:123)
        at persistence.EmployeeDAO.create(EmployeeDAO.java:53)
        at xml.CrmCaddyXMLParser.saveEmployee(CrmCaddyXMLParser.java:585)
        at xml.CrmCaddyXMLParser.endElement(CrmCaddyXMLParser.java:196)
        at org.apache.xerces.parsers.AbstractSAXParser.endElement(Unknown Source)
        at org.apache.xerces.impl.dtd.XMLDTDValidator.endNamespaceScope(Unknown Source)
        at org.apache.xerces.impl.dtd.XMLDTDValidator.handleEndElement(Unknown Source)
        at org.apache.xerces.impl.dtd.XMLDTDValidator.endElement(Unknown Source)
        at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanEndElement(Unknown Source)
        at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl$FragmentContentDispatcher.dispatch(Unknown Source)
        at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source)
        at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
        at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
        at org.apache.xerces.parsers.XMLParser.parse(Unknown Source)
        at org.apache.xerces.parsers.AbstractSAXParser.parse(Unknown Source)
        at xml.CRMCaddy.main(CRMCaddy.java:131)
15:46:55,344 DEBUG JDBCTransaction:82 - rollback
15:46:55,344 DEBUG SessionImpl:585 - transaction completion
15:46:55,344 DEBUG SessionImpl:2242 - flushing session
15:46:55,344 DEBUG SessionImpl:2435 - Flushing entities and processing referenced collections
15:46:55,344 DEBUG SessionImpl:2529 - Updating entity: [persistence.hibernate.Employee#13498699]
15:46:55,354 ERROR HibernateUtils:158 - Failed to rollback/close session:
net.sf.hibernate.PropertyValueException: not-null property references a null or transient value: persistence.hibernate.Employee.con_lastname
        at net.sf.hibernate.impl.SessionImpl.checkNullability(SessionImpl.java:1276)
        at net.sf.hibernate.impl.SessionImpl.flushEntity(SessionImpl.java:2567)
        at net.sf.hibernate.impl.SessionImpl.flushEntities(SessionImpl.java:2454)
        at net.sf.hibernate.impl.SessionImpl.flushEverything(SessionImpl.java:2256)
        at net.sf.hibernate.impl.SessionImpl.flush(SessionImpl.java:2235)
        at persistence.hibernate.HibernateUtils.closeSession(HibernateUtils.java:84)
        at persistence.hibernate.HibernateUtils.persistHibernateBean(HibernateUtils.java:153)
        at persistence.EmployeeDAO.create(EmployeeDAO.java:53)
        at xml.CrmCaddyXMLParser.saveEmployee(CrmCaddyXMLParser.java:585)
        at xml.CrmCaddyXMLParser.endElement(CrmCaddyXMLParser.java:196)
        at org.apache.xerces.parsers.AbstractSAXParser.endElement(Unknown Source)
        at org.apache.xerces.impl.dtd.XMLDTDValidator.endNamespaceScope(Unknown Source)
        at org.apache.xerces.impl.dtd.XMLDTDValidator.handleEndElement(Unknown Source)
        at org.apache.xerces.impl.dtd.XMLDTDValidator.endElement(Unknown Source)
        at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanEndElement(Unknown Source)
        at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl$FragmentContentDispatcher.dispatch(Unknown Source)
        at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source)
        at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
        at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
        at org.apache.xerces.parsers.XMLParser.parse(Unknown Source)
        at org.apache.xerces.parsers.AbstractSAXParser.parse(Unknown Source)
        at xml.CRMCaddy.main(CRMCaddy.java:131)
15:46:55,374  INFO CrmCaddyXMLParser:631 - Create new employee.  Action failed for EID [99999] CID [579845] Prospect CID [53]
15:46:55,374 DEBUG CrmCaddyXMLParser:204 - Completed employee processing


Top
 Profile  
 
 Post subject:
PostPosted: Mon Aug 30, 2004 4:26 pm 
Proxool Developer
Proxool Developer

Joined: Tue Aug 26, 2003 10:42 am
Posts: 373
Location: Belgium
In closeSession(), you flush() then close() the session. This is ok except when you roll back a transaction.

In that situation, as per the doc, the session should be discarded immediately and nothing should be done with it anymore.

Unfortunately, in your situation, you first try to commit and discover the 'null' property. You then issue a rollback on the transaction then decide to flush the session again. This will try to persist the changes held in your session back to the db...

See what I mean ?


Top
 Profile  
 
 Post subject:
PostPosted: Mon Aug 30, 2004 4:38 pm 
Beginner
Beginner

Joined: Sat Dec 20, 2003 5:09 pm
Posts: 38
Ahhhhhh.

So the flush fails, and since it fails the close never occurs. Got it.

Many, many thanks for the note.

I just have to add how super this product is. The support is simply amazing. Thanks to all who put in so much effort ...


Top
 Profile  
 
 Post subject:
PostPosted: Mon Aug 30, 2004 4:54 pm 
Beginner
Beginner

Joined: Sat Dec 20, 2003 5:09 pm
Posts: 38
bertrand ,

I just updated my code to not flush on errors and it now works as expected.

Again, thanks for the heads-up.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Aug 30, 2004 5:03 pm 
Proxool Developer
Proxool Developer

Joined: Tue Aug 26, 2003 10:42 am
Posts: 373
Location: Belgium
rich wrote:
I just updated my code to not flush on errors and it now works as expected.


... except your session won't be closed after a succefull commit (and won't be deassociated from the ThreadLocal...


Top
 Profile  
 
 Post subject:
PostPosted: Mon Aug 30, 2004 5:13 pm 
Beginner
Beginner

Joined: Sat Dec 20, 2003 5:09 pm
Posts: 38
I think I should be cleaning up properly. I'm still calling my closeSession() method and in that method I'm always calling session.close(). The difference is that I hacked my closeSession() method to take a boolean parameter. Something like this:

Code:
/***************************************************************************
    * Closes the Hibernate session for the current thread
    *
    * @params errors Indicates there was a session error and so the
    * session.flush() method should not be called.
    * @throws HibernateException
    **************************************************************************/
    public static void closeSession(boolean errors)
       throws HibernateException
   {
       Session s = (Session) session.get();
       session.set(null);

       if (s != null)
       {
          if(errors == false)
          {
              s.flush();
          }
          else
          {
              _log.info("closeSession() called - not flushing due to error flag state");
          }
         
          s.close();

          if(_log.isDebugEnabled())
          {
             _log.debug("Closing session");
          }
       }
       else
       {
          if(_log.isDebugEnabled())
          {
             _log.debug("S was null, not calling close()");
          }
       }
    }


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 6 posts ] 

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.