2010-07-22 33 views
8

Tôi đang làm việc trên một ứng dụng web với Wicket, Spring và Hibernate và tôi đã gặp một vấn đề với việc cập nhật các bản ghi. Tôi đã xác minh rằng phương thức saveOrUpdate được gọi và dữ liệu trong đối tượng miền đã thay đổi. Tuy nhiên, đầu ra SQL không hiển thị bất kỳ thay đổi nào đối với cơ sở dữ liệu đã được tạo (ví dụ UPDATE) và bản ghi bị ảnh hưởng chưa được cập nhật.Hibernate không cập nhật hồ sơ - Wicket

Tôi đoán nó có ý nghĩa hơn khi sử dụng cập nhật() nhưng tôi saveOrUpdate() không quản lý để tạo bản ghi mới, nhưng nó không cập nhật chúng. Tôi đã xác minh rằng phương thức này được gọi, và UserVO được truyền đi có chứa các trường được cập nhật. Dưới đây là phương pháp DAO:

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

Dưới đây là tập tin bất động sản của tôi:

 
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

Đây là đậu sessionfactory trong 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; 

}

Trả lời

25

Hibernate thường trì hoãn cập nhật cho đến khi phiên giao dịch bị xóa. Để kiểm tra xem đây có phải là vấn đề trong trường hợp của bạn hay không, hãy chèn getSession().flush() sau câu lệnh cập nhật của bạn.

Bạn quản lý giao dịch bằng cách nào? Tự động xả sẽ diễn ra tự động khi phiên được cam kết, nhưng nếu bạn có cấu hình giao dịch bị lỗi, bạn có thể kết thúc kết nối JDBC nhưng không thực hiện giao dịch được liên kết với phiên Hibernate.

Edit: Dựa trên bản cập nhật của bạn, tôi thấy rằng FlushMode được thiết lập để KHÔNG BAO GIỜ tại một số hàng:

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

tôi nghi ngờ đây là vấn đề. Nó làm cho phiên không bao giờ tự động tuôn ra - thường là những gì bạn muốn làm trong một giao dịch chỉ đọc, không phải khi bạn sửa đổi dữ liệu. Có vẻ như bạn đang chạy mà không có giao dịch (tự động đặt thành true - không được khuyến nghị bằng cách này). Javadoc cho OpenSessionInViewFilter cung cấp một số manh mối:

Bộ lọc này theo mặc định sẽ không xóa phiên Hibernate, với chế độ xả được đặt thành FlushMode.NEVER. Nó giả sử được sử dụng kết hợp với các giao dịch tầng dịch vụ quan tâm đến việc xả: Trình quản lý giao dịch hiện hoạt sẽ tạm thời thay đổi chế độ xả sang FlushMode.AUTO trong giao dịch đọc-ghi, với chế độ flush được đặt lại thành FlushMode.NEVER ở cuối của mỗi giao dịch. Nếu bạn dự định sử dụng bộ lọc này mà không có giao dịch, hãy xem xét thay đổi chế độ xả mặc định (thông qua thuộc tính "flushMode").

Nói cách khác, bạn có hai lựa chọn: hoặc là thiết lập flushMode trên OpenSessionInViewFilter của bạn để AUTO, hoặc tắt autocommit và cấu hình một người quản lý giao dịch như HibernateTransactionManager.

+0

Có, bắt tốt +1 –

+0

Cảm ơn bạn rất nhiều! Thêm phương thức getSession(). Flush() vào phương thức cập nhật đã hoạt động. Tôi đã thử thiết lập flushMode để "AUTO" trong OpenSessionInViewFilter, nhưng tôi vẫn phải tự gọi getSession(). Flush() để chạy cập nhật (với autocommitt và tắt). – John

+0

Với flushMode được đặt thành AUTO và có tính năng tự động vô hiệu hóa, tôi có thể làm cho nó hoạt động bằng cách thực hiện; Transaction tr = getSession(). BeginTransaction(); getSession(). cập nhật (vo); tr.commit() ;. Cảm ơn một lần nữa – John

6

Vì bạn đang sử dụng Spring, tôi khuyên bạn nên sử dụng PlatformTransactionManager của Spring để quản lý các giao dịch của bạn. Là một phần của quản lý giao dịch, Spring tự động xóa phiên. Điều này có nghĩa là bạn không phải lo lắng về bất kỳ khía cạnh nào trong các mã này.

Spring có OpenSessionInViewFilter nối trình quản lý giao dịch với các phiên khởi động/xả và bạn có thể chú thích các phương thức của mình bằng @Transactional của Spring để cho biết rằng bạn muốn giao dịch 'ghi' cho một phương thức cụ thể. Điều này sẽ cập nhật hồ sơ của bạn.

Các vấn đề liên quan