0
    @RequestMapping("/testing") 
    @Transactional
    public String testing(HttpServletRequest request, final ModelMap model) 
    {               

        Criteria criteria = session.getCurrentSession().createCriteria(Student.class);      
        criteria.setReadOnly(true);

        criteria.add(Restrictions.eq("id", "ID12345"));

        List<Student> result =  criteria.list();                

        Student abc = result.get(0);

        abc.setFirstname("AAA");                

        Criteria criteria2 = session.getCurrentSession().createCriteria(Student.class);             
        criteria2.setReadOnly(false);


        criteria2.add(Restrictions.eq("id", "ID12345"));

        result =  criteria2.list();             

        Student abc2 = result.get(0);

        abc2.setFirstname("BBB");

        return "testing";
    }

As the code above, it has setReadOnly to true for criteria, so firstName will not be AAA (in database), but it has reset the setReadOnly to false for criteria2, why the firstname didn't become BBB (in database)?

Sam YC
  • 10,725
  • 19
  • 102
  • 158
  • do you not need to save the entity? – Scary Wombat Aug 30 '16 at 02:15
  • @ScaryWombat I already simplify the scenario, in my actual code, it has few layer of service and model class and few method in between. So I created this simplified scenario to find out the root cause of my issue. Yes, I want to save the entity, but I wouldn't be able to remove `criteria.setReadOnly(true)` (it is in other method). – Sam YC Aug 30 '16 at 02:18
  • What if you place the second call in a method marked @Transactional(propagation = Propagation.REQUIRES_NEW) to start new transaction? – StanislavL Aug 30 '16 at 06:51

1 Answers1

1

Ok, after some time of research, I managed to find out the reason.

While the first query load up the object, hibernate put the object in persistent context and mark the object as read-only. Meaning the object will not be flushed in the end.

During second call to load up the object, hibernate fetch the object in persistent context instead of making call to database again, because the fetch is based on primary key. Since it is loaded from persistent context, it will be still in read-only state.

In order to let the object back to flush-able again, we can use setReadOnly(Object entity, boolean readOnly) to set back the readOnly of the object.

Sam YC
  • 10,725
  • 19
  • 102
  • 158
  • 1
    Had a similar problem. Early in the transaction my entity was loaded as `read-only=true`, later trying to re-load the entity with `read-only=false` - I saw that the Hibernate entity state was still `READONLY`. By running `if session.isReadOnly(entity) { session.setReadOnly(entity, true); }` it reset the entity state to `MANAGED` and allowed my update to persist. `NOTE:` I had to set `read-only=false` BEFORE I made the change to the entity, or it wouldn't be persisted. – Thomas Taylor Jan 08 '20 at 18:21