I am trying to update an object in hibernate but I don't understand why it is not getting updated in the db. Can anyone please help?
Controller class
package com.petclinic.controller;
import com.petclinic.ClinicService;
import com.petclinic.Owner;
@Controller
@RequestMapping("/owners/{ownerId}/edit")
@SessionAttributes({"owner"})
public class EditOwnerForm {
private final ClinicService clinicService;
@Autowired
public EditOwnerForm(ClinicService clinicService) {
this.clinicService = clinicService;
}
@InitBinder
public void setAllowedFields(WebDataBinder dataBinder) {
dataBinder.setDisallowedFields("id");
}
//Mapping for GET Request
@RequestMapping(method = RequestMethod.GET)
public String setupForm(@PathVariable("ownerId") int ownerId, Model model) {
Owner owner = this.clinicService.loadOwner(ownerId);
model.addAttribute(owner);
model.addAttribute("action", "editowner");
return "owners/form";
}
//Mapping for POST Request
@RequestMapping(method = RequestMethod.POST)
public String processSubmit(@ModelAttribute Owner owner, /*BindingResult result,*/ SessionStatus status) {
System.out.println(owner.toString());
System.out.println("Inside EditOwner processSubmit method");
this.clinicService.editOwner(owner);
status.setComplete();
return "redirect:/forms/owners/" + owner.getId();
}
}
DAO Class
@Transactional
public void editOwner(Owner owner) {
System.out.println("Inside editOwner method" + owner.getCity());
sessionFactory.getCurrentSession().update(owner);
}
I am trying to update the city of the owner but I it's not getting updated. Here is what I get in the console. Within the editOwner method I get the owner's city so I believe the value is passed properly. It's something to do with the method. I tried with update, merge, saveOrUpdate but nothing seems to work.
`Inside Welcome Controller
/forms
Delivering the owner search page
owner's name searched :
Hibernate: select owner0_.ID as ID0_, owner0_.FIRST_NAME as FIRST2_0_, owner0_.LAST_Name as LAST3_0_, owner0_.ADDRESS as ADDRESS0_, owner0_.CITY as CITY0_, owner0_.TELEPHONE as TELEPHONE0_ from OWNERS owner0_ where owner0_.LAST_Name like ?
FindOwner result from db [[Owner@3f305 id = 1, new = false, lastName = 'Franklin', firstName = 'George', address = '110 W. Liberty St.', city = 'Madison', telephone = '6085551023'], [Owner@1a5214b id = 2, new = false, lastName = 'Davis', firstName = 'Betty', address = '638 Cardinal Ave.', city = 'Sun Prairie', telephone = '6085551749'], [Owner@2ccaf3 id = 3, new = false, lastName = 'Rodriquez', firstName = 'Eduardo', address = '2693 Commerce St.', city = 'McFarland', telephone = '6085558763'], [Owner@c0290c id = 4, new = false, lastName = 'Davis', firstName = 'Harold', address = '563 Friendly St.', city = 'Windsor', telephone = '6085553198'], [Owner@1c6e8c1 id = 5, new = false, lastName = 'McTavish', firstName = 'Peter', address = '2387 S. Fair Way', city = 'Madison', telephone = '6085552765'], [Owner@1daee61 id = 6, new = false, lastName = 'Coleman', firstName = 'Jean', address = '105 N. Lake St.', city = 'Monona', telephone = '6085552654'], [Owner@58526a id = 7, new = false, lastName = 'Black', firstName = 'Jeff', address = '1450 Oak Blvd.', city = 'Monona', telephone = '6085555387'], [Owner@8ad65b id = 8, new = false, lastName = 'Escobito', firstName = 'Maria', address = '345 Maple St.', city = 'Madison', telephone = '6085557683'], [Owner@ff1cc0 id = 9, new = false, lastName = 'Schroeder', firstName = 'David', address = '2749 Blackhawk Trail', city = 'Madison', telephone = '6085559435'], [Owner@b89c6e id = 10, new = false, lastName = 'Estaban', firstName = 'Carlos', address = '2335 Independence La.', city = 'Waunakee', telephone = '6085555487'], [Owner@262743 id = 11, new = false, lastName = 'sarawagi', firstName = 'shivang', address = 'whitefield', city = 'bangalore', telephone = '12345'], [Owner@dbc09c id = 12, new = false, lastName = 'Hood', firstName = 'Robin', address = 'Atlanta', city = 'Newyork', telephone = '0989890829'], [Owner@142464f id = 13, new = false, lastName = 'Hearty', firstName = 'Hale', address = 'taiwan', city = 'Atlanta', telephone = '8967867868']]
Multiple Owners found
Returning owners/list
Hibernate: select owner0_.ID as ID0_0_, owner0_.FIRST_NAME as FIRST2_0_0_, owner0_.LAST_Name as LAST3_0_0_, owner0_.ADDRESS as ADDRESS0_0_, owner0_.CITY as CITY0_0_, owner0_.TELEPHONE as TELEPHONE0_0_ from OWNERS owner0_ where owner0_.ID=?
Hibernate: select owner0_.ID as ID0_0_, owner0_.FIRST_NAME as FIRST2_0_0_, owner0_.LAST_Name as LAST3_0_0_, owner0_.ADDRESS as ADDRESS0_0_, owner0_.CITY as CITY0_0_, owner0_.TELEPHONE as TELEPHONE0_0_ from OWNERS owner0_ where owner0_.ID=?
[Owner@1df63f9 id = 8, new = false, lastName = 'Escobito', firstName = 'Maria', address = '345 Maple St.', city = 'Mumbai', telephone = '6085557683']
Inside EditOwner processSubmit method
Inside editOwner method Mumbai
Hibernate: select owner0_.ID as ID0_0_, owner0_.FIRST_NAME as FIRST2_0_0_, owner0_.LAST_Name as LAST3_0_0_, owner0_.ADDRESS as ADDRESS0_0_, owner0_.CITY as CITY0_0_, owner0_.TELEPHONE as TELEPHONE0_0_ from OWNERS owner0_ where owner0_.ID=?
`
Code for DAO class
package com.petclinic.hibernate;
import java.util.Collection;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import com.petclinic.Clinic;
import com.petclinic.Owner;
* <p>Note that transactions are declared with annotations and that some methods
* contain "readOnly = true" which is an optimization that is particularly
* valuable when using Hibernate (to suppress unnecessary flush attempts for
* read-only operations).
@Repository
@Transactional
//HibernateClinic behaves as a DaoImpl/Repository class
public class HibernateClinic implements Clinic {
private SessionFactory sessionFactory;
@Autowired
public HibernateClinic(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
@Transactional(readOnly = true)
@SuppressWarnings("unchecked")
public Collection<Owner> findOwners(String lastName) {
return sessionFactory.getCurrentSession().createQuery("from Owner owner where owner.lastName like :lastName")
.setString("lastName", lastName + "%").list();
}
@Transactional(readOnly = true)
public Owner loadOwner(int id) {
return (Owner) sessionFactory.getCurrentSession().load(Owner.class, id);
}
public void storeOwner(Owner owner) {
//A transient object without an id will always be saved by hibernate's save() or persist() method
sessionFactory.getCurrentSession().save(owner);
}
@Transactional
public void editOwner(Owner owner) {
//A transient object without an id will always be saved by hibernate's save() or persist() method
System.out.println("Inside editOwner method" + owner.getCity());
sessionFactory.getCurrentSession().update(owner);
}
}
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_5.xsd">
<display-name>PetClinic</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/applicationContext.xml
</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/dispatcher-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/forms/*</url-pattern>
</servlet-mapping>
<filter>
<filter-name>hibernateFilter</filter-name>
<filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
<init-param>
<param-name>sessionFactoryBeanName</param-name>
<param-value>sessionFactory</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>hibernateFilter</filter-name>
<url-pattern>/forms/*</url-pattern>
</filter-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
dispatcher-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
<context:component-scan base-package="com.petclinic"/>
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource"
p:basename="messages"/>
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix">
<value>/WEB-INF/view/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
</beans>
ApplicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
<context:annotation-config />
<!-- <context:property-placeholder> XML element automatically registers a new PropertyPlaceholderConfigurer
bean in the Spring Context. -->
<context:property-placeholder location="classpath:database.properties" />
<!-- enable the configuration of transactional behavior based on annotations -->
<tx:annotation-driven transaction-manager="hibernateTransactionManager"/>
<!-- Creating DataSource -->
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${database.driver}" />
<property name="url" value="${database.url}" />
<property name="username" value="${database.user}" />
<property name="password" value="${database.password}" />
</bean>
<!-- To persist the object to database, the instance of SessionFactory interface is created.
SessionFactory is a singleton instance which implements Factory design pattern.
SessionFactory loads hibernate.cfg.xml and with the help of TransactionFactory and ConnectionProvider
implements all the configuration settings on a database. -->
<!-- Configuring SessionFactory -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="annotatedClasses">
<list>
<value>com.petclinic.Owner</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
<prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
</props>
</property>
</bean>
<!-- Configuring Hibernate Transaction Manager -->
<bean id="hibernateTransactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
</beans>
I believe I found out the problem. I am using an OpenSessionInView Filter with HibernateTransaction Manager. 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. I don't know why Hibernate transaction manager is not flushing the session. So I added getCurrentSession.flush()
after the update method & it worked. Any comments?
I even configured FlushMode of OSIV Filter as commit/Auto & checked, it didn't worked so had to resort to manually flushing the session.