29

I was quite surprised to find out that Hibernate automatically saves dirty objects at the end of transaction, without explicit calls to something like

dao.save(object)

I have in mind the situation described by this thread

My question is: is there a way to disable this behaviour? At first glance this automatic saving seems rather dangerous because you need to know which objects are connected to the session and which not and it seems pretty easy to save something by mistake. Can you tell me what the benefits of this automatic-saving approach are? I hardly see any. I'd like to always explicitly call dao.save(object) to update anything.

I heard of one possible workaround to this, which is using an entityInterceptor on your sessionFactory. This custom entityInterceptor would override the findDirty method to never find anything dirty, but in such case I suppose dao.save won't also work. Any ideas?

Community
  • 1
  • 1
machinery
  • 3,793
  • 4
  • 41
  • 52
  • 1
    It is indeed one of the most annoying things about hibernate. Consider using ebean instead :) – Hoof Jan 25 '17 at 15:43

2 Answers2

15

I agree, you should not flush manually. My experience of webapp developer said that FlushMode should be set to "AUTO". But sometimes I need to disable dirty check (for validation of data, validating data in database and data return by forms or services). For that I create a special class and disabled dirty check by changing the FLUSHMODE:

@Component
public class ValidateRefPaysService implements IValidateRefPaysService {

    ...

    @Autowired
    @Qualifier("sessionFactory")
    private SessionFactory sessionFactory;

    @Override
    @Transactional(readOnly=true) 
    public void validate(RefPays refPays) throws BusinessException {
        
        try {
            sessionFactory.getCurrentSession().setFlushMode(FlushMode.MANUAL);
        
            if ( refPays.getId() != null ) {
                RefPays refPaysBase = refPaysDAO.getById(refPays.getId());
                if ( refPaysBase != null )  {
                    throw new BusinessException("id already exists in database.", "RefPays.savePays.id.alreadyexist", "refPays.savePays.id.alreadyexist");
                }
            }
        } finally {
            sessionFactory.getCurrentSession().setFlushMode(FlushMode.AUTO);
        }
    }
}
xav
  • 5,452
  • 7
  • 48
  • 57
Grégory
  • 1,473
  • 1
  • 17
  • 28
5

To disable automatic state management set the flush mode on your session to MANUAL. You can then call session.flush() to actually write out all dirty entities associated with your session.

Stefan Haberl
  • 9,812
  • 7
  • 72
  • 81
  • 9
    Hmm... I don't really want to disable Hibernate automatic flushing - this would cause me to loose the benefits of Hibernate's performance-related facilities. I would just want only those objects to be dirty on which I explicitly call dao.save or dao.update... – machinery Oct 16 '12 at 07:58
  • 1
    You can't. IMHO that's one of the main advantages to go for an ORM: to track which of your objects are dirty automatically and issue the necessary SQLs – Stefan Haberl Oct 16 '12 at 15:16
  • 9
    @StefanHaberl how is this one of the main advantages? How often do you write code and not explicitly issue "save" on entities that you atually want to save? Ofc the dirty-checking should still be there, so that if you issues save and the entity is not dirty, no query will be issued to the database. – Hoof Jan 25 '17 at 15:42