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