2010-07-22 56 views
8

我正在与Wicket,Spring和Hibernate的Web应用程序工作,我遇到了更新记录的问题。我已验证saveOrUpdate方法已被调用,并且域对象中的数据已更改。然而,SQL输出不会显示对数据库所做的任何更改(例如UPDATE),并且受影响的记录尚未更新。休眠不更新记录 - Wicket

我猜想它更有意义使用update(),但我saveOrUpdate()确实设法创建新记录,但它不会更新它们。我已验证此方法被调用,并且传递的UserVO确实包含更新的字段。这里的DAO方法:

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

这里是我的属性文件:

 
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

下面是applicationContext.xml中SessionFactory的豆:

 
<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; 

}

回答

25

休眠经常推迟更新直到会话被刷新。要测试您的情况是否出现问题,请在更新声明后插入getSession().flush()

您如何管理交易?当会话被提交时,刷新会自动发生,但是如果你有一个错误的事务配置,你最终可能会提交JDBC连接,但不会提交绑定到Hibernate会话的事务。

编辑:根据您的更新,我看到了从来没有在一些一行FlushMode设置:

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

我怀疑这就是问题所在。它会导致会话永远不会自动刷新 - 这通常是您想要在只读事务中执行的操作,而不是在修改数据时执行的操作。看起来你在没有事务的情况下运行(autocommit设置为true - 这不是推荐的方式)。对于OpenSessionInViewFilter的Javadoc提供了一些线索:

这个过滤器将默认不刷新Hibernate的Session,设置为FlushMode.NEVER刷新模式。它假定与关注刷新的服务层事务组合使用:在读写事务期间,活动事务管理器将临时更改刷新模式为FlushMode.AUTO,并在最后将刷新模式重置为FlushMode.NEVER的每笔交易。如果您打算在没有事务的情况下使用此过滤器,请考虑更改默认的刷新模式(通过“flushMode”属性)。

换句话说,你有两个选择:要么在你的OpenSessionInViewFilter为自动设置flushMode,或者,关闭自动提交,并配置一个事务管理器,如HibernateTransactionManager

+0

是的,赶上+1 – 2010-07-22 23:25:17

+0

非常感谢!将getSession()。flush()添加到更新方法的确行得通。我曾尝试在OpenSessionInViewFilter中将flushMode设置为“AUTO”,但我仍然必须手动调用getSession()。flush()来运行更新(自动提交开启和关闭)。 – John 2010-07-23 06:50:58

+0

将flushMode设置为AUTO并禁用了自动提交功能后,我可以通过执行来使其工作; Transaction tr = getSession()。beginTransaction(); 。的getSession()更新(VO); tr.commit();.再次感谢 – John 2010-07-23 07:02:20

6

由于您使用的是Spring,我建议您使用Spring的PlatformTransactionManager来管理事务。作为事务管理的一部分,Spring会自动刷新会话。这意味着您不必担心代码中的这些方面。

Spring有一个OpenSessionInViewFilter,挂钩到事务管理器以启动/刷新会话,并且您可以使用Spring的@Transactional注释您的方法,以表明您需要针对特定​​方法的“写入”事务。这应该更新您的记录。