0

I already search in forums, and i tried many things without succes.

I want at the end on a transactional method, and only at the end, to save only hibernate object for whom i will use explicitly the Hibernate getHibernateTemplate().saveOrUpdate() method, and NOT dirty ones, that i only modify using setters.

My need will be clearer after reading my service layer code:

For simplicity purpose, i will summarize my code.

Service layer:

@Service("cartService")
public class CartServiceImpl extends AbstractServiceImpl<Cart> implements
        CartService {

   @Autowired 
   private CartDao cartDao;

   @Transactional(readOnly = false)
   public Cart updateCart1(){

            Cart cartA = cartDao.findById(1);
            cartA.setTotal=(5);

            Cart cartB = cartDao.findById(1);
            cartB.setTotal=(5);     
            CartDao.Update(cartB);
   }
}

So, what i need, is at the end of the method updateCart1() is to save the change of cartB, BUT Not to save the change of cartA.

Dao layer:

NB: cartDao's methods (findById, saveOrUpdate) call the HibernateTemplate one.

public T update(T entite) {
    getHibernateTemplate().saveOrUpdate(entite);
    return entite;
}

public T findById(Serializable id) {
    return getHibernateTemplate().get(this.clazz, id);
}

I didn't want that Dao's method act on database outside a transactionnal service layer method. And i wanted them to be executed in database at the end of a transaction defined on the service layer. Thus, in hibernate spring configuration file:

<prop key="connection.autocommit">false</prop> 

Note that i am using OpenSessionInViewFilter for Lazyu loading purpose. So in my XML file:

<filter>
  <filter-name>OpenSessionInViewFilter</filter-name>
  <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
  <init-param>
     <param-name>singleSession</param-name>
     <param-value>false</param-value>
  </init-param> 
</filter>

NB: These cart cartDao's methods are working fine in a normal scenario. But not in the one i'm describing. And "@Transactional" is correctly configured and work fine two.

Problem: With this code, i get the two objects (cartA and cartB) changed in database, while i dont want to modify cartA, for whom i didn't call explicitly the HibernateTemplate's saveOrUpdate method.

After searching in forums, i tried to make the hibernate FLUSH mode to FLUSH_NEVER. But at the execution of CartDao.Update(cartB) i get this exception:

org.springframework.dao.InvalidDataAccessApiUsageException: Write operations are not allowed in read-only mode (FlushMode.MANUAL): Turn your Session into FlushMode.COMMIT/AUTO or remove 'readOnly' marker from transaction definition.

Please, can you help me?

Sbousfiha
  • 3
  • 4
  • 1
    Why do you modify an entity if your goal is to leave it unmodified? – JB Nizet Oct 26 '13 at 13:01
  • This is a good existencial question. - I need to prevent modifying an object in many place in the same transactional method. - I find this way more stylish. – Sbousfiha Oct 26 '13 at 13:21
  • But you're fighting against Hibernate. I don't find it stylish, but hackish. Even if you manage to do it (and you probably won't), every other developer (including yourself, some weeks or months later) won't understand why something which should be updated given the normal Hibernate behavior is not updated, because of this hack. – JB Nizet Oct 26 '13 at 13:28
  • I did not realize that it was the normal Hibernate behavior. I'm not an hibernate expert. You convince me. And if requiered, i will change my logic. Thank you JB. – Sbousfiha Oct 26 '13 at 13:36
  • Read the hibernate documentation about entity states. Every change made to an attached entity will be persisted, transparently, without any need to call save, update(), merge(), saveOrUpdate() or any other method. That's one of the key features of hibernate. You get an entity graph from the database, modify it somehow, and every change you made is transparently and automatically persisted. – JB Nizet Oct 26 '13 at 13:39

2 Answers2

2

You could call

getHibernateTemplate().getSession().evict(cartA);

to remove it from the session.

The best option though is to not modify cartA. If you need to calculate something using a cartA property you could make a copy of that property.

MattR
  • 6,908
  • 2
  • 21
  • 30
0

You can use org.hibernate.StatelessSession interface instead of org.hibernate.Session.

In javadocs you see:

A stateless session does not implement a first-level cache nor interact with any second-level cache, nor does it implement transactional write-behind or automatic dirty checking, nor do operations cascade to associated instances. Collections are ignored by a stateless session. Operations performed via a stateless session bypass Hibernate's event model and interceptors. Stateless sessions are vulnerable to data aliasing effects, due to the lack of a first-level cache.

Amir Pashazadeh
  • 7,170
  • 3
  • 39
  • 69
  • Thank you Amir. But according to your explanation, StatelessSession has its inconveniences. 1- Data aliasing. 2- I will no more take benefit of some hibernate cach capabilities. Do you agree? In which case, i prefer to respect the behaviour of normal hibernate session. – Sbousfiha Oct 26 '13 at 18:13