i'm using Hibernate 3.0 with Tapestry 4.0 beta 11, using long sessions. i have a test application Wiki, and the edit page is updating my WikiPage object's properties correctly, and calling the DAO, which reports the correct changed values, but yet issues no SQL so the changed object is not persisted.
example:
1. retrieve WikiPage name:b, contents:b
2. update contents:bb > click Submit
3. log output results in:
[DEBUG] 3210277 wiki.components.WikiPageCRUD starting a transaction
[DEBUG] 3210277 wiki.dao.HibernateUtil Starting new database transaction in this thread.
[DEBUG] 3210277 wiki.dao.HibernateUtil Opening new Session for this thread.
[DEBUG] 3210277 wiki.dao.WikiPageDAOHibernate entered editPage
id: 2
name: b
contents: bb
created: 2005-10-27
modified: Fri Oct 28 17:42:00 EDT 2005
[DEBUG] 3210327 wiki.dao.HibernateUtil Committing database transaction of this thread.
[DEBUG] 3210327 wiki.dao.HibernateUtil Closing Session of this thread.
so... how can my object clearly be changed yet hibernate doesn't recognize it as changed?
thanks,
jeff
Hibernate version: 3.0
Mapping documents:
WikiPage.hbm.xml
Code:
<!DOCTYPE
hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class
name="wiki.model.WikiPage"
table="pag_pages_tbl">
<id
name="id"
column="pag_id">
<generator class="native" />
</id>
<property
name="name"
type="string">
<column
name="pag_name"
not-null="true" />
</property>
<property
name="contents"
type="string">
<column
name="pag_content"
length="65535"
not-null="true" />
</property>
<property name="dateCreated" type="date">
<column name="pag_date_created" not-null="true"/>
</property>
<property name="dateModified" type="date">
<column name="pag_date_modified" not-null="true"/>
</property>
</class>
</hibernate-mapping>
Code between sessionFactory.openSession() and session.close():
using HibernateFilter from 3.0 open session in view from older version of hibernate's wiki:
Code:
public class HibernateFilter
implements
Filter {
private static Log log = LogFactory.getLog(HibernateFilter.class);
public void destroy() {}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException,
ServletException {
try {
// We don't start the database transaction here, but when first needed
chain.doFilter(request, response);
// Commit any pending database transaction.
HibernateUtil.commitTransaction();
}
finally {
// No matter what happens, close the Session.
HibernateUtil.closeSession();
}
}
public void init(FilterConfig filterConfig) throws ServletException {
log.info("Servlet filter init, now opening/closing a Session for each request.");
}
}
HibernateUtil from book or wiki:
Code:
public class HibernateUtil {
private static Configuration configuration;
private static Log log = LogFactory.getLog(HibernateUtil.class);
private static SessionFactory sessionFactory;
private static final ThreadLocal threadSession = new ThreadLocal();
private static final ThreadLocal threadTransaction = new ThreadLocal();
// Create the initial SessionFactory from the default configuration files
static {
try {
configuration = new Configuration().configure();
configuration.addResource("wiki/model/WikiPage.hbm.xml");
sessionFactory = configuration.buildSessionFactory();
}
catch (Throwable ex) {
// We have to catch Throwable, otherwise we will miss
// NoClassDefFoundError and other subclasses of Error
log.error("Building SessionFactory failed.", ex);
throw new ExceptionInInitializerError(ex);
}
}
/**
* Start a new database transaction.
*/
public static void beginTransaction() {
// Would be written as a no-op in an EJB container with CMT
Transaction tx = (Transaction) threadTransaction.get();
if (tx == null) {
log.debug("Starting new database transaction in this thread.");
tx = getSession().beginTransaction();
threadTransaction.set(tx);
}
}
/**
* Closes the Session local to the thread.
*/
public static void closeSession() {
// Would be written as a no-op in an EJB container with CMT
Session s = (Session) threadSession.get();
threadSession.set(null);
if (s != null && s.isOpen()) {
log.debug("Closing Session of this thread.");
s.close();
}
}
/**
* Commit the database transaction.
*/
public static void commitTransaction() {
// Would be written as a no-op in an EJB container with CMT
Transaction tx = (Transaction) threadTransaction.get();
try {
if (tx != null && !tx.wasCommitted() && !tx.wasRolledBack()) {
log.debug("Committing database transaction of this thread.");
tx.commit();
}
threadTransaction.set(null);
}
catch (HibernateException ex) {
rollbackTransaction();
throw ex;
}
}
/**
* Retrieves the current Session local to the thread. <p/> If no Session is
* open, opens a new Session for the running thread.
*
* @return Session
*/
public static Session getSession() {
// With CMT, this should return getSessionFactory().getCurrentSession()
// and do nothing else
Session s = (Session) threadSession.get();
if (s == null) {
log.debug("Opening new Session for this thread.");
s = getSessionFactory().openSession();
threadSession.set(s);
}
return s;
}
/**
* Returns the SessionFactory used for this static class.
*
* @return SessionFactory
*/
public static SessionFactory getSessionFactory() {
/*
* Instead of a static variable, use JNDI: SessionFactory sessions =
* null; try { Context ctx = new InitialContext(); String jndiName =
* "java:hibernate/HibernateFactory"; sessions =
* (SessionFactory)ctx.lookup(jndiName); } catch (NamingException ex) {
* throw new RuntimeException(ex); } return sessions;
*/
return sessionFactory;
}
/**
* Rollback the database transaction.
*/
public static void rollbackTransaction() {
// Would be written as a no-op in an EJB container with CMT (maybe
// setRollBackOnly...)
Transaction tx = (Transaction) threadTransaction.get();
try {
threadTransaction.set(null);
if (tx != null && !tx.wasCommitted() && !tx.wasRolledBack()) {
log.debug("Tyring to rollback database transaction of this thread.");
tx.rollback();
}
}
finally {
closeSession();
}
}
}
WikiPageDAO excerpt:
Code:
public WikiPage editPage(WikiPage page) throws DAOException {
log.debug("entered editPage "
+ "\nid: " + page.getId()
+ "\nname: " + page.getName()
+ "\ncontents: " + page.getContents()
+ "\ncreated: " + page.getDateCreated()
+ "\nmodified: " + page.getDateModified());
try {
HibernateUtil.getSession().lock(page, LockMode.NONE);
HibernateUtil.getSession().update(page);
return page;
}
catch (HibernateException e) {
String msg = "The DAO could not update page.";
log.error(msg, e);
throw new DAOException(msg, e);
}
}
code in Tapestry page that uses the DAO after processing the Update form:
Code:
log.debug("starting a transaction");
HibernateUtil.beginTransaction();
wikiPage.setDateModified(new Date());
wdao.editPage(wikiPage);
Full stack trace of any exception that occurs: no errors...
Name and version of the database you are using: mySql 4.0.22
The generated SQL (show_sql=true): nothing generated...
Debug level Hibernate log excerpt: