I have this non standard situation where i need to update object inside readOnly Hibernate transaction. The thing is, i load many other objects, change them within that transaction, but only one should be saved, rest roll-backed. The database i work on is Postgresql 8.4
I`m not sure i understand docs correctly, but making a service method:
@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
should result in opening new RW transaction explicitly for that save.
The main thing is, this is not working:
@Transactional(readOnly = true)
public class PersonService {
@Resource(name="sessionFactory")
private SessionFactory sessionFactory;
public void add(Person person){
person.setFirstName("changed its name");
save(person);
}
@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
public void save(Person person) {
Session session = sessionFactory.getCurrentSession();
session.save(person);
session.flush();
}
}
After that i get
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.hibernate.exception.GenericJDBCException: Could not execute JDBC batch update
From controller, call the ‘add’ method. ‘add’ is in readOnly mode, and it passes the Person object to ‘save’ method, which should open new Transaction and save to DB. In my project in the ‘add’ method i have many other ‘Person’ objects loaded, which should not be saved.
The reason i need the method to be readOnly is that i load many more objects farther in code 🙂 Rolling them back is last thing i want to do.
Is it possible to do that this way?
Transactions are typically applied by generating an implementation for a service interface (you don’t show that you’re implementing an interface, that might just be your example code?)
Anyway, the point is that in that case, simply calling save(…) is not going through the wrapper, it’s just running the method on the target object. You would need to inject a reference from the service to itself, so it could call itself and get the wrapping applied. That is:
And the call stack would look something like:
(what you’re describing sounds like logging an error message of some sort, which is where I’ve used requiresNew transaction marking (in J2EE though, but I think the point carries))