New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Optimistic lock does not work correctly when REST call is received #26365
Comments
did i create the issue incorrectly ? or in wrong place ? |
I have seen same issue |
Hi, Same issue here. @Dennisber00 : To bypass the issue, I wrapped the merge method of the entityManager like this :
I flagged versioned entities with
And the encapsulated one :
Pay attention to the cascadeType in the |
@Dennisber00 this all looks like expected, setting the version manually and not having a transaction around that code should throw that exception. I am going to close this now and please use StackOverflow if you have more questions around JPA usage. |
@snicoll Have you read my description carefully ? Of course, it is excepted to have en exception, but I showed a sample (even created a small project to show it) when NO EXCEPTION is thrown if it is executed behind a REST call. So it is a bug then. Please, re-read this part of my description one more time: "II. But it does not work at all when it is called as part of REST request handling. Because OpenEntityManagerInViewFilter delegates OpenEntityManagerInViewInterceptor to create a new entity manager instance which creates one hibernate session to process entire request. In this case on line 2 the "found" entity is cached by StatefulPersistenceContext which leads to a problem on line 6, because the session is still alive/active StatefulPersistenceContext still contains "found" entity in L1 cache. In this case entity state is resolved as PERSISTENT in DefaultMergeEventListener.onMerge method. It means that "found" entity is processed as PERSISTENT in entityIsPersistent method of DefaultMergeEventListener. entityIsPersistent does not check if the version is changed. Because of it "found" entity is saved on line 6 without any optimistic lock exception. I guess this method should work always identical and produces the optimistic lock exception. Am i right ?" I will create a new identical issue if this is not be re-opened. Because i believe it is the bug. |
No. I've shared why I think that code is invalid already. If you read an entity outside of a transaction and attempt to save it the way you do, you're opening yourself to inconsistencies like this. You think this is a Spring issue but what you use from it simply delegates to JPA, that's why I mentioned to ask usage question on SO.
This is a waste of both our time as it will be closed. |
@snicoll This is only a simplified sample (invalid as you wish) to demonstrate this problem. Of course, in this sample it is only JPA delegation. You are right here. Unfortunately, i am not allow to share an Enterprise project (which is definitely way more complex than this sample) to show a real example where this problem was faced. No exception is thrown because of OSIV or OpenSessionInViewFilter creating a session per each REST request (spring logic and not related to JPA) + lack of transaction (human error). And OSIV is enabled by default. It means that in a real big project where spring/spring boot is used to simplify developers life ("easy to use" is one of spring slogan, right ?) if human factor is applied (or i would say when applied) and @transaction is lost somewhere in between (this situation is easy to imagine, unfortunately) a developer will face inconsistency in behavior (as you correctly mentioned) which is really hard to identify in a spot where exception must be thrown. Based on this i think it is still a spring issue, not JPA or something else. |
Correct. There is a warning in the startup log of your sample to tell you how to disable it. We strongly encourage you to disable it if you don't need it. If you want more context as why OSIV is enabled by default, see spring-projects/spring-boot#7107 |
Affects: Spring boot 2.4.1 and earlier
Affects: spring-boot-starter-data-jpa 2.4.1 and earlier
Affects: spring-boot-starter-web 2.4.1 and earlier
Description: I found out that optimistic lock does not work correctly in a case when a method, which can produce it, is called via REST controller.
As an example, the following method of a service must produce an optimistic lock exception every time it is called (let assume that a book entity is already created in the database):
I. Because there is no @transaction annotation above the method and a read only transaction as well as hibernate session are created on line 2, then entity is loaded and got a DETACHED status. After that on line 6 a new transaction as well as hibernate session are created to merge "found" entity changes. Finally DefaultMergeEventListener (hibernate) produces a new optimistic lock exception, because the entity is processed as DETACHED (entityIsDetached method) and the version field was changed. It works correctly when it is called internally in an application.
II. But it does not work at all when it is called as part of REST request handling. Because OpenEntityManagerInViewFilter delegates OpenEntityManagerInViewInterceptor to create a new entity manager instance which creates one hibernate session to process entire request. In this case on line 2 the "found" entity is cached by StatefulPersistenceContext which leads to a problem on line 6, because the session is still alive/active StatefulPersistenceContext still contains "found" entity in L1 cache. In this case entity state is resolved as PERSISTENT in DefaultMergeEventListener.onMerge method. It means that "found" entity is processed as PERSISTENT in entityIsPersistent method of DefaultMergeEventListener. entityIsPersistent does not check if the version is changed. Because of it "found" entity is saved on line 6 without any optimistic lock exception.
I guess this method should work always identical and produces the optimistic lock exception. Am i right ?
I created a demo project to produce this problem:
https://github.com/Dennisber00/spring-opt-log-bug
Step to reproduce in the demo project
No optimistic lock exception:
Optimistic lock exception:
The text was updated successfully, but these errors were encountered: