Robert Bowen
Robert Bowen

Reputation: 487

HibernateTemplate save performs inserts but not updates

I have a typical Spring / Hibernate setup. Here's my spring config:

<context:annotation-config />

<context:component-scan base-package="com.myco.myapp.modules" />

<tx:annotation-driven transaction-manager="transactionManager"/>

<bean id="sessionFactory"
...     
</bean>

<bean id="transactionManager"
    class="org.springframework.orm.hibernate3.HibernateTransactionManager">
  <property name="sessionFactory" ref="sessionFactory" />
</bean>

I have a BaseRepository:

@Transactional(propagation = Propagation.MANDATORY)
public final T save(final T entity) throws RepositoryException {
    try {
        getHibernateTemplate().save(entity);
        return entity;
    } catch (DataAccessException e) {
        throw new EntityCouldNotBeSavedException(getPersistentClass(),
            e);
    }
}

And a Repository class that extends it:

@Repository
public class PersonRepositoryImpl extends BaseRepositoryImpl<Person, String>

And a Service:

@Service
public class PersonServiceImpl {
  @Autowired
  private PersonRepository _personRespository;

I call the following method, saveSomeStuff(), an when I insert using BaseRepository.save() it works perfectly. But when I try to update, it doesn't make the change:

@Override
@Transactional
public void saveSomeStuff() {

    try {

        Person existingPerson = _personRespository.findById("1");

        existingPerson.setName("John");

        _personRespository.save(existingPerson);

        Person dbExistingPerson = _personRespository.findById("1");

        // This prints "John".
        System.out.println(dbExistingPerson.getName());

        Person newPerson = new Person();
        newPerson.setName("Jack");
        _personRespository.save(newPerson);

    } catch (RepositoryException e) {
        e1.printStackTrace();

    }
}

I thought I might have a transaccionality problem, but as I said, upon leaving the Service method the new Person is persisted in the database. In the log I see:

insert into person ...

However, the update I made is not persisted, and there is no error and no 'update' sql statement in the log. I thought the HibernateTemplate.save() method might be the problem but from within the saveSomeStuff() method, after loading the Person from the database, I do a System.out, and the Person loaded from the database has the updated name.

What am I missing here?

Upvotes: 0

Views: 7017

Answers (4)

MRTJ
MRTJ

Reputation: 139

I had stumbled upon the same problem. The entity was getting inserted into the database, but while updating some of the columns where not getting updated and there were no errors in the log. After going through the entity class, I figured out that I had annotated some of my fields as below

@Column(name = "CREATED_DT", updatable = false)
private Date createdOn;

After removing the updatable attribute from the annotation, the update was working fine.

Upvotes: 0

Robert Bowen
Robert Bowen

Reputation: 487

Figured out the problem. If I had included my Entity class, someone probably would have seen it sooner than me.

@Entity
@Cache(usage = CacheConcurrencyStrategy.READ_ONLY)
@Immutable
@Table(name = "PEOPLE")
public class Person {
  ...
}

Initially I was getting a cache error:

java.lang.UnsupportedOperationException: Can't write to a readonly object

The quick solution? Add the @Immutable annotation. But if you read the docs for it:

An immutable entity may not be updated by the application. 
Updates to an immutable entity will be ignored, but no exception is thrown.

Which explains why 1) updates were being ignored and 2) no exceptions were being thrown.

So I got rid of the @Immutable annotation and changed Cache to:

 @Cache(usage = CacheConcurrencyStrategy.READ_WRITE)

And now everything works fine.

In summary: rtfm.

Upvotes: 0

Chily
Chily

Reputation: 1

Save method will Persists an entity. Will assign an identifier if one doesn't exist. If one does, it's essentially doing an update. Returns the generated ID of the entity.

Upvotes: 0

mrembisz
mrembisz

Reputation: 12880

There is a separate method, saveOrUpdate(entity). You can use it if you don't want hibernate to generate id while saving.

Upvotes: 1

Related Questions