In a hobby project I'm currently doing to teach myself Hibernate and Spring MVC, I have an import option for movies from TMDb.
During this import I create new actors (when not available yet) and finally movie itself.
The strange thing is that the first time I import a movie, everything works as expected but when I want to import a new movie after clicking around in the application, I got the following exception:
I've set OpenSessionInViewFilter to use a SingleSession due to cascading issues, could that be interfering with this functionality?
As this is my first project using Hibernate and Spring MVC, I don't know where to start debugging this issue or which information I can provide to shed some more light on the issue.
Any help is highly appreciated.
Open Session In View should be regarded as an anti-pattern; not only because it breaks the encapsulation of data access from the web tier, but because it allows for inefficient data access if not used sparingly. Reliance on Open Session in View can easily result in large number of SQL selects being executed from the web tier, a reappearance of the N+1 Selects problem. If used, the Open Session In View should be considered a last resort, with resulting data access in the web tier considered a bug in the application. Do not place too much reliance on the Open Session in View pattern. Use it only as a last resort to avoid more embarrassing user interface bugs.
One other option that is not mentioned (many are not a fan of this either) is to map the necessary information to a DTO to send to the view layer. Libraries like Dozer can be used to map domain to dto and vice versa. Now I am not suggesting this for every use case but if you run into a situation where the previous links suggestions do not work than certainly I find it preferable to holding the session open.
My suggestion is to get rid of the OpenSessionInView filter and address the underlying cause of the ensuing LazyInitializationExceptions that will likely occur.
That said onto your original issue:
Somewhere you are probably are trying to saveOrUpdate some newly created object and the id is already present in the persistence context. Persistent ids are required to be unique within the context. You can either find the entity causing the violation and evict it from the cache or you can make use of merge.
Thanks for you answer, this did get rid of the exception, however now the "first" movie is partially overwritten by the second one, which does not seem to be created itself.
Is there a way to remove all current objects from a session before (or after) processing a new import?
What surprised me was that I needed to make the changes in a file which did not show up in the stacktrace, but I guess that has something to do with the AOP part.
About the SessionInView part. I was having issues with retrieving and especially updating lazy loaded entities (as it is a hobby project, it has been a while since I've tackled that issue, so I'm not exactly sure). It happened before I started working on the import part.
Due to my domain model, I would rather not fetch all relations eagerly, but I guess that would be a different thing I need to check out when I've solved this.
After reading the code to look for a place to test the session.evict(), I found a piece of line which might be causing the issue and sure enough it fixed the issue.
It turned out I was using a class variable which was filled during the import, however the variable was only initialized during the class initialization, which obvious isn't thread safe. Probably a beginners mistake.
When initializing the variable before starting the import routine fixed the issue.
So now it's up to fixing the OSIV.
Thanks for your pointer about the session.evict(). Without it I doubt I would have found the issue.