0

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>
underdog
  • 4,447
  • 9
  • 44
  • 89
  • Consider using `spring-data-jpa` instead of DAO. – MariuszS Jan 07 '14 at 18:36
  • 2
    I don't see any transaction in your code, so nothing is committed. – JB Nizet Jan 07 '14 at 18:40
  • but for another method I used hibernate save() method. It worked fine without @Transactional annotation. I've put edited the code put Transactional over the editOwner method & its class still it doesn't work. – underdog Jan 07 '14 at 18:43
  • Shouldn't your DAO or your service method be transactional? – Hrishikesh Jan 07 '14 at 18:45
  • can you show the code for this 'other' method? including the code that invokes this 'other' method.. are you sure that there is no transaction anywhere for the other method also? – Praba Jan 07 '14 at 18:47
  • Added the complete DAO class – underdog Jan 07 '14 at 18:49
  • Doesn't merge return back the entity? The updated entity I mean. If you are verifying for the entity which is passed in. It will not be updated. You have to inspect the echoed back entity for the updated value. – Hrishikesh Jan 07 '14 at 18:54
  • can you tell what is the meaning of this line in the console `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=?` I don't know what is it passing to the db. I checked with merge, update, saveorupdate doesn't work in anycase. – underdog Jan 07 '14 at 18:59
  • That line is just the log msg of what hibernate is doing behind the scenes. it is querying for the Owner object from the database. I'm assuming this happens just before the merge. What i'm wondering is if this statement get printed, why not the update statement? Can you paste the complete hibernate logs? It might be due to the transaction is not committed/flushed. – Praba Jan 07 '14 at 19:04
  • I've updated the logs in the question; true the update query is not generated by hibernate – underdog Jan 07 '14 at 19:11
  • 1
    this.clinic.editOwner(owner); --- Change that to getClinic().editOwner(owner); ... of course you'll also need to write the actual getter. Your DAO is being treated as static and I don't know if spring is working with it properly when you do that ie. your transactions aren't being wrapped. – zmf Jan 07 '14 at 19:17
  • Clinic is an interface which is injected in the controller which declares the editOwner method. Is there any way to check if the Transactions are working fine or not? – underdog Jan 07 '14 at 19:18
  • http://stackoverflow.com/a/10808563/2231632 Did you try zmf's suggestion? – Praba Jan 07 '14 at 19:21
  • Implemented a new Service layer transaction class in the code; still it doesn't work; I believe the problem is not with the transaction as hibernate is not even creating the UPDATE sql query. A transaction problem would only stop from committing to the db but atleast an update query should be generated. – underdog Jan 07 '14 at 19:53
  • Please post the full controller class. – zmf Jan 07 '14 at 19:55
  • Controller class updated – underdog Jan 07 '14 at 19:58
  • I have a question if transaction is not working will a new object will be saved in database by save() method? – underdog Jan 07 '14 at 20:20
  • You do have a transaction manager in your application context, right? – zmf Jan 07 '14 at 21:12

2 Answers2

0

Place

<context:component-scan base-package="com.petclinic"/>

in applicationContext.xml.

zmf
  • 9,095
  • 2
  • 26
  • 28
  • I have removed the final & put @Autowire at field level `@Autowired private ClinicService clinicService;` Still doesn't work Also updated the applicationContext here – underdog Jan 08 '14 at 15:04
  • 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? – underdog Jan 08 '14 at 17:26
  • I even configured FlushMode of OSIV Filter as commit/Auto & checked, it didn't worked so had to resort to manually flushing the session. – underdog Jan 08 '14 at 17:27
  • Turn up your log levels to see if your transactions are starting / committing – zmf Jan 08 '14 at 18:32
  • just developing the app for learning so didn't setup the logs in the app yet – underdog Jan 08 '14 at 18:41
0

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.

underdog
  • 4,447
  • 9
  • 44
  • 89