Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hibernate is not updating record - Wicket

I'm working on a web application with Wicket, Spring and Hibernate and I've come across a problem with updating records. I have verified that the saveOrUpdate method is invoked, and that the data in the domain object has changed. The SQL-output does however not display that any changes to the database has been made (UPDATE in example) and the affected record has not been updated.

I would guess it makes more sense to use update() but I saveOrUpdate() does manage to create new records, but it does not update them. I have verified that this method IS invoked, and the UserVO that is passed does contain the updated fields. Here's the DAO method:

public class SkuldwebDAOImpl extends HibernateDaoSupport implements SkuldwebDAO {
    public void updateUser(UserVO userVO) {
        getSession().saveOrUpdate(userVO);
    }
}

Here's my property file:

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost/skuldweb_dev;AUTO=MULTI;CURSOR=READONLY
jdbc.username=
jdbc.password=
hibernate.dialect=org.hibernate.dialect.MySQLDialect
hibernate.show_sql=true
hibernate.use_outer_join=true
hibernate.cache.use_query_cache=true hibernate.cache.use_second_level_cache=true hibernate.cache.provider=org.hibernate.cache.HashtableCacheProvider
hibernate.schemaUpdate=true

Here's the sessionFactory bean in applicationContext.xml:

<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">${hibernate.dialect}</prop>
                <prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
                <prop key="use_outer_join">${hibernate.use_outer_join}</prop>
                <prop key="hibernate.cache.use_second_level_cache">${hibernate.cache.use_second_level_cache}</prop>
                <prop key="hibernate.cache.use_query_cache">${hibernate.cache.use_query_cache}</prop>
                <prop key="hibernate.cache.provider_class">${hibernate.cache.provider}</prop>
                <prop key="hibernate.connection.pool_size">10</prop>
                <prop key="hibernate.connection.autocommit">true</prop>
                <prop key="hibernate.jdbc.batch_size">1000</prop>
                <prop key="hibernate.bytecode.use_reflection_optimizer">true</prop>
            </props>
        </property>
        
        <property name="annotatedClasses">
            <list>
                <value>com.upbeat.app.skuldweb.domain.UserVO</value>
                <value>com.upbeat.app.skuldweb.domain.UserLevelVO</value>
</list> </property> <property name="schemaUpdate" value="${hibernate.schemaUpdate}"/> </bean>

Hopefully one of you can help me out.

Updated Here's some info from the log (onSubmit() sets off these entries in the log -- the last entry should be when the request is being redirected to another page (after the record should have been updated).


[DEBUG] 2010-07-23 00:29:26,302 :org.springframework.orm.hibernate3.support.OpenSessionInViewFilter.lookupSessionFactory(OpenSessionInViewFilter.java:239): Using SessionFactory 'sessionFactory' for OpenSessionInViewFilter
[DEBUG] 2010-07-23 00:29:26,302 :org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:214): Returning cached instance of singleton bean 'sessionFactory'
[DEBUG] 2010-07-23 00:29:26,302 :org.springframework.orm.hibernate3.support.OpenSessionInViewFilter.doFilterInternal(OpenSessionInViewFilter.java:181): Opening single Hibernate Session in OpenSessionInViewFilter
[DEBUG] 2010-07-23 00:29:26,302 :org.springframework.orm.hibernate3.SessionFactoryUtils.doGetSession(SessionFactoryUtils.java:318): Opening Hibernate Session
[DEBUG] 2010-07-23 00:29:26,303 :org.hibernate.impl.SessionImpl.(SessionImpl.java:247): opened session at timestamp: 5242215490777088
[TRACE] 2010-07-23 00:29:26,303 :org.hibernate.impl.SessionImpl.setFlushMode(SessionImpl.java:1316): setting flush mode to: NEVER
[DEBUG] 2010-07-23 00:29:26,305 :org.apache.wicket.Session.getPage(Session.java:700): Getting page [path = 4:userprofile_form, versionNumber = 0]
[DEBUG] 2010-07-23 00:29:26,306 :org.apache.wicket.markup.html.form.persistence.CookieValuePersister.getCookie(CookieValuePersister.java:210): Unable to find Cookie with name=userprofile_form.email and request URI=/upbeat-app-skuld-web/
[TRACE] 2010-07-23 00:29:26,308 :org.hibernate.engine.IdentifierValue.isUnsaved(IdentifierValue.java:127): id unsaved-value: 0
[TRACE] 2010-07-23 00:29:26,308 :org.hibernate.event.def.AbstractSaveEventListener.getEntityState(AbstractSaveEventListener.java:546): detached instance of: com.upbeat.app.skuldweb.domain.UserVO
[TRACE] 2010-07-23 00:29:26,308 :org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsDetached(DefaultSaveOrUpdateEventListener.java:228): updating detached instance
[TRACE] 2010-07-23 00:29:26,308 :org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performUpdate(DefaultSaveOrUpdateEventListener.java:295): updating [com.upbeat.app.skuldweb.domain.UserVO#1]
[TRACE] 2010-07-23 00:29:26,310 :org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performUpdate(DefaultSaveOrUpdateEventListener.java:346): updating [com.upbeat.app.skuldweb.domain.UserVO#1]
[TRACE] 2010-07-23 00:29:26,311 :org.hibernate.engine.Cascade.cascade(Cascade.java:138): processing cascade ACTION_SAVE_UPDATE for: com.upbeat.app.skuldweb.domain.UserVO
[TRACE] 2010-07-23 00:29:26,312 :org.hibernate.engine.CascadingAction$5.cascade(CascadingAction.java:239): cascading to saveOrUpdate: com.upbeat.app.skuldweb.domain.UserLevelVO
[TRACE] 2010-07-23 00:29:26,312 :org.hibernate.engine.IdentifierValue.isUnsaved(IdentifierValue.java:127): id unsaved-value: 0
[TRACE] 2010-07-23 00:29:26,312 :org.hibernate.event.def.AbstractSaveEventListener.getEntityState(AbstractSaveEventListener.java:546): detached instance of: com.upbeat.app.skuldweb.domain.UserLevelVO
[TRACE] 2010-07-23 00:29:26,312 :org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsDetached(DefaultSaveOrUpdateEventListener.java:228): updating detached instance
[TRACE] 2010-07-23 00:29:26,313 :org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performUpdate(DefaultSaveOrUpdateEventListener.java:295): updating [com.upbeat.app.skuldweb.domain.UserLevelVO#1]
[TRACE] 2010-07-23 00:29:26,313 :org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performUpdate(DefaultSaveOrUpdateEventListener.java:346): updating [com.upbeat.app.skuldweb.domain.UserLevelVO#1]
[TRACE] 2010-07-23 00:29:26,313 :org.hibernate.engine.Cascade.cascade(Cascade.java:173): done processing cascade ACTION_SAVE_UPDATE for: com.upbeat.app.skuldweb.domain.UserVO
[DEBUG] 2010-07-23 00:29:26,314 :org.apache.wicket.RequestCycle.setRequestTarget(RequestCycle.java:644): replacing request target org.apache.wicket.request.target.component.listener.ListenerInterfaceRequestTarget@676067951[Page class = com.upbeat.app.skuldweb.web.user.UserProfilePage, id = 4, version = 0]->userprofile_form->interface org.apache.wicket.markup.html.form.IFormSubmitListener.IFormSubmitListener (request paramaters: [RequestParameters  componentPath=4:userprofile_form pageMapName=null versionNumber=0 interfaceName=IFormSubmitListener componentId=null behaviorId=null urlDepth=-1 parameters={[email protected],userprofile__form2_hf_0=} onlyProcessIfPathActive=false]) with [BookmarkablePageRequestTarget@1030849724 pageClass=com.upbeat.app.skuldweb.web.user.UserProfilePage]

Update 2 Here's the UserVO without the getters/setters

@Entity
@Table(name = "USERS")
@NamedQueries({
    @NamedQuery(name = "user.getById", query = "from UserVO item where item.id = :id"),
    @NamedQuery(name = "user.getAllUsers", query = "from UserVO item order by item.registerDate desc"),
    @NamedQuery(name = "user.countAll", query = "select count(item) from UserVO item"),
    @NamedQuery(name = "user.getByUsername", query = "from UserVO item where item.username = :username"),
    @NamedQuery(name = "user.authenticate", query = "from UserVO item where item.username = :username AND item.passwordHash = :passwordHash")
})
public class UserVO extends BaseVO {

@Id  
@GeneratedValue(strategy = GenerationType.AUTO)  
@Column(name = "ID")  
protected long id;  

@OneToOne(cascade = CascadeType.ALL)
protected UserLevelVO userLevelVO;

@Basic
@Column(name = "USERNAME")
protected String username;

@Basic
@Column(name = "PASSWORD_HASH")
protected String passwordHash;

@Basic
@Column(name = "EMAIL")
protected String email;

@Temporal(TemporalType.TIMESTAMP)
@Column(name = "REGISTER_DATE")
protected Date registerDate;

@Temporal(TemporalType.TIMESTAMP)
@Column(name = "LAST_LOGIN_DATE")
protected Date lastLoginDate;

}

like image 606
John Avatar asked Jul 22 '10 21:07

John


2 Answers

Hibernate often defers updates until the session is flushed. To test if this is the issue in your case, insert a getSession().flush() after your update statement.

How do you manage transactions? Flushing will occur automatically when the session is committed, but if you have a faulty transaction configuration, you may end up committing the JDBC connection but not committing the transaction tied to the Hibernate session.

Edit: Based on your update, I see that FlushMode is set to NEVER at some row:

[TRACE] 2010-07-23 00:29:26,303 :org.hibernate.impl.SessionImpl.setFlushMode(SessionImpl.java:1316): setting flush mode to: NEVER

I suspect this is the problem. It causes the session never to flush automatically - which is usually what you want to do in a read-only transaction, not when you modify data. It seems like you are running without transactions (autocommit set to true - which is not recommended by the way). The Javadoc for OpenSessionInViewFilter provides some clues:

This filter will by default not flush the Hibernate Session, with the flush mode set to FlushMode.NEVER. It assumes to be used in combination with service layer transactions that care for the flushing: The active transaction manager will temporarily change the flush mode to FlushMode.AUTO during a read-write transaction, with the flush mode reset to FlushMode.NEVER at the end of each transaction. If you intend to use this filter without transactions, consider changing the default flush mode (through the "flushMode" property).

In other words, you have two options: either set flushMode on your OpenSessionInViewFilter to AUTO, or, turn off autocommit and configure a transaction manager such as HibernateTransactionManager.

like image 66
waxwing Avatar answered Nov 06 '22 05:11

waxwing


Since you are you using Spring, I would recommend that you use Spring's PlatformTransactionManager to manage your transactions. As part of transaction management Spring automatically flushes the session. This means that you don't have to worry about any of these aspects in your code.

Spring has a OpenSessionInViewFilter that hooks up to the transaction manager to start/flush sessions and you can annotate your methods with Spring's @Transactional to indicate that you want a 'write' transaction for a particular method. This should update your records.

like image 28
Vineeth Avatar answered Nov 06 '22 04:11

Vineeth