2010-07-22 13 views
8

Ich arbeite an einer Webanwendung mit Wicket, Spring und Hibernate, und ich bin auf ein Problem mit der Aktualisierung von Datensätzen gestoßen. Ich habe überprüft, dass die saveOrUpdate-Methode aufgerufen wurde und dass sich die Daten im Domänenobjekt geändert haben. Die SQL-Ausgabe zeigt jedoch nicht an, dass Änderungen an der Datenbank vorgenommen wurden (UPDATE in Beispiel) und der betroffene Datensatz wurde nicht aktualisiert.Hibernate aktualisiert Datensatz nicht - Wicket

Ich denke, es macht mehr Sinn, update() zu verwenden, aber ich saveOrUpdate() schafft es, neue Datensätze zu erstellen, aber es aktualisiert sie nicht. Ich habe überprüft, dass diese Methode aufgerufen wird, und das übergebene UserVO enthält die aktualisierten Felder. Hier ist die DAO-Methode:

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

Hier ist mein Eigentum Datei:

 
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

Hier ist die session Bohne 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.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; 

}

Antwort

25

Hibernate oft aufschiebt Updates, bis die Sitzung geleert wird. Um zu testen, ob dies in Ihrem Fall der Fall ist, fügen Sie nach Ihrer Aktualisierungsanweisung eine getSession().flush() ein.

Wie verwalten Sie Transaktionen? Das Flushing wird automatisch ausgeführt, wenn die Sitzung festgeschrieben wird. Wenn Sie jedoch eine fehlerhafte Transaktionskonfiguration haben, können Sie möglicherweise die JDBC-Verbindung festschreiben, aber nicht die an die Hibernate-Sitzung gebundene Transaktion festschreiben.

Edit: Basierend auf dem Update, ich sehe, dass Flushmode gesetzt irgend Reihe NIE:

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

Ich vermute, das ist das Problem. Dadurch wird die Sitzung nie automatisch geleert. Dies ist normalerweise das, was Sie in einer schreibgeschützten Transaktion tun möchten, nicht wenn Sie Daten ändern. Es scheint, als ob Sie ohne Transaktionen laufen (Autocommit auf True gesetzt - was übrigens nicht empfohlen wird). Die Javadoc OpenSessionInViewFilter liefert einige Hinweise:

Dieser Filter wird standardmäßig nicht in den Ruhezustand Session bündig mit dem Flush-Modus FlushMode.NEVER eingestellt. Es wird davon ausgegangen, dass es in Kombination mit Service-Layer-Transaktionen verwendet wird, die das Flushing betreffen: Der aktive Transaktionsmanager ändert während einer Lese-/Schreib-Transaktion vorübergehend den Flush-Modus in FlushMode.AUTO, wobei der Flush-Modus am Ende auf FlushMode.NEVER zurückgesetzt wird jeder Transaktion. Wenn Sie diesen Filter ohne Transaktionen verwenden möchten, sollten Sie den Standard-Flush-Modus (über die Eigenschaft "flushMode") ändern.

Mit anderen Worten, Sie haben zwei Möglichkeiten: Entweder setzen flushMode auf OpenSessionInViewFilter auf AUTO oder drehen autocommit off und einen Transaktionsmanager wie HibernateTransactionManager konfigurieren.

+0

Ja, guter Fang +1 –

+0

Vielen Dank! Das Hinzufügen von getSession(). Flush() zur Update-Methode hat funktioniert. Ich habe versucht, flushMode auf "AUTO" im OpenSessionInViewFilter zu setzen, aber ich musste immer getSession() manuell aufrufen. Flush() um das Update (mit Autocommit ein und aus) zu starten. – John

+0

Wenn flushMode auf AUTO gesetzt wurde und Autocommit deaktiviert wurde, konnte ich es funktionieren lassen; Transaktion tr = getSession(). BeginTransaction(); getSession() .update (vo); tr.commit() ;. Danke noch einmal – John

6

Da Sie Spring verwenden, würde ich empfehlen, Spring's PlatformTransactionManager zu verwenden, um Ihre Transaktionen zu verwalten. Im Rahmen der Transaktionsverwaltung spült Spring die Sitzung automatisch. Dies bedeutet, dass Sie sich in Ihrem Code keine Gedanken über diese Aspekte machen müssen.

Spring verfügt über einen OpenSessionInViewFilter, der sich mit dem Transaktionsmanager verbindet, um Sitzungen zu starten/zu leeren, und Sie können Ihre Methoden mit Spring @Transactional versehen, um anzuzeigen, dass Sie eine Transaktion für eine bestimmte Methode schreiben möchten. Dies sollte Ihre Aufzeichnungen aktualisieren.

Verwandte Themen