While testing JPA optimistic locking, I have simple entity and corresponding service/controller. Locking property looks like this:
@Version
@Column(name = "opt_lock", nullable = false)
private short optLock;
Testing scenario. I have 1 preexisting record. Entity contains ID, optLock, and 2 data fields valueA and valueB. Both are set to 1. .save method call has breakpoint on it, and it's wrapped in try-catch catching all RuntimeExceptions. Same is whole transaction initiated via TransactionTemplate.
On controller I call PUT method to update values, valueA and valueB respectively, to 2-5. Entity is read by ID, only values valueA and valueB are updated, no touching lock field. Hangs on .save method call breakpoint, which is configured to block single thread only.
Same action again, but with values 200-1. Thread is also blocked.
I unpause second update, verify that data were correctly updated to 200-1, and in issued statement correct 200-1 values are sent, also optLock value used in update statement was the one which exist in DB in preexisting record. Correct.
I unpause thread related to first update, I see, that there is attempt to update record with correct values 2-5, correct optLock was used, ie. the one which exist in db before this action. At this moment, combination ID-optLock does not exist in db. Thus this record cannot be updated. And it wasn't. Correct!
But ... no exception. Why?
In attempt to debug it, I tried to remove net.ttddyy.datasource-proxy from project if it's not swallowing it (it doesn't), I tried if the whole scenario starts to fail if I remove @Version
annotation (it does), I tried to debug through hibernate code, but I did not find any problem at all.
Any suggestions what can cause missing exception?
UPDATE: replaced spring stuff with plain EntityManager and it's the same. Tried to run it outside of Intellij IDEA, as it turned out, it sometimes can do very surprising stuff with your db calls, and it's the same. More surprisingly (to me) if I introduce flush&clear calls and put breakpoint on them, Thread suspended on line after flush and clear somehow holds lock to persistence context or something, but second thread just suspends until first one is done, so this cannot be used to simulate lock exception, thus I believe also cannot cause problem in real-life if access to persistence context is synchronized (maybe in default setting, which would be my current setting).