2010-07-22 15 views
8

Estoy trabajando en una aplicación web con Wicket, Spring e Hibernate y me he encontrado con un problema con la actualización de registros. He verificado que se invoca el método saveOrUpdate y que los datos en el objeto de dominio han cambiado. Sin embargo, la salida de SQL no muestra que se haya realizado ningún cambio en la base de datos (ACTUALIZAR en el ejemplo) y el registro afectado no se ha actualizado.Hibernate no está actualizando registro - Wicket

Supongo que tiene más sentido usar update() pero saveOrUpdate() logra crear nuevos registros, pero no los actualiza. He verificado que este método se invoca, y el UserVO que se pasa contiene los campos actualizados. Aquí está el método DAO:

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

Aquí está mi archivo de propiedades:

 
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

Aquí está el frijol sessionFactory en 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.r[email protected]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 [[email protected] 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; 

}

Respuesta

25

Hibernate menudo aplaza actualizaciones hasta que la sesión se vacía. Para comprobar si este es el problema en su caso, inserte un getSession().flush() después de su declaración de actualización.

¿Cómo se gestionan las transacciones? El enrojecimiento se producirá automáticamente cuando se haya comprometido la sesión, pero si tiene una configuración de transacción defectuosa, puede terminar comprometiendo la conexión JDBC pero sin comprometer la transacción vinculada a la sesión de Hibernate.

Editar: En base a su actualización, veo que FlushMode se establece en Nunca en algún consecutivas:

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

sospecho que este es el problema. Hace que la sesión nunca se vacíe automáticamente, que generalmente es lo que desea hacer en una transacción de solo lectura, no cuando modifica los datos. Parece que se está ejecutando sin transacciones (confirmación automática establecida en verdadero, lo cual no es recomendable por cierto). El Javadoc para OpenSessionInViewFilter ofrece algunas pistas:

Este filtro por defecto no tirar de la sesión de Hibernate, con el modo de descarga se establece en FlushMode.NEVER. Se supone que se utilizará en combinación con transacciones de la capa de servicio que se preocupan por la descarga: el administrador de transacciones activo cambiará temporalmente el modo de descarga a FlushMode.AUTO durante una transacción de lectura-escritura, con el modo de descarga restablecido a FlushMode.NEVER al final de cada transacción. Si tiene la intención de utilizar este filtro sin transacciones, considere cambiar el modo de descarga predeterminado (a través de la propiedad "flushMode").

En otras palabras, usted tiene dos opciones: o bien establecer flushMode en su OpenSessionInViewFilter en AUTO, o, apague confirmación automática y configurar un administrador de transacciones tales como HibernateTransactionManager.

+0

Sí, buena captura +1 –

+0

¡Muchas gracias! Agregar getSession(). Flush() al método de actualización funcionó. Intenté configurar flushMode en "AUTO" en OpenSessionInViewFilter, pero aún tuve que invocar manualmente getSession(). Flush() para ejecutar la actualización (con autocommitt activado y desactivado). – John

+0

Con flushMode establecido en AUTO y al deshabilitar la confirmación automática, pude hacerlo funcionando; Transacción tr = getSession(). BeginTransaction(); getSession(). update (vo); tr.commit() ;. Gracias de nuevo – John

6

Dado que está utilizando Spring, le recomendaría que utilice SpringTassa PlatformManager para gestionar sus transacciones. Como parte de la gestión de transacciones, Spring vacía automáticamente la sesión. Esto significa que no tiene que preocuparse por ninguno de estos aspectos en su código.

Spring tiene un OpenSessionInViewFilter que se conecta al gestor de transacciones para iniciar/vaciar las sesiones y puede anotar sus métodos con @Transactional de Spring para indicar que desea una transacción de "escritura" para un método en particular. Esto debería actualizar tus registros.

Cuestiones relacionadas