Reputation: 1407
I'm facing this very unusual error.
I have this JpaRepository<SomeObject, Long>
public interface SomeRepository extends JpaRepository<SomeObject, Long> {
@Query("select someObject from SomeObject someObject where someObject.id = ?1")
public SomeObject getSomeObject(int id);
}
It works fine, and when I try to get SomeObject with ID that does not exist, it simply returns null and I handle it and proceed further.
However, when I introduced multiple instances of my application (say 2), and hid them behind a loadbalancer. I perform this operation (as a script), where it retrieves/creates/deletes SomeObject on repeat.
When I have only one instance, I run the script which does: retrieval (returns null) -> creation of SomeObject, deletion of SomeObject and repeat retrieval (returns null) -> ... etc
Everything works fine and as expected ^
In my multiple instances setup, load balancer reroutes requests to instances interchangeably. Meaning, the operations now happen in this order:
Instance (1) retrieval (returns null)
Instance (2) creation of SomeObject
Instance (1) deletion of SomeObject
And on the next iteration, some weird behavior is observed!
Instance (2) retrieval (here instead of returning null, Spring all of a sudden throws following exception):
Caused by: org.springframework.orm.jpa.JpaObjectRetrievalFailureException: Unable to find somePackage.SomeObject with id 1; nested exception is javax.persistence.EntityNotFoundException: Unable to find somePackage.SomeObject with id 1
at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:389) ~[spring-orm-4.3.8.RELEASE.jar!/:4.3.8.RELEASE]
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:246) ~[spring-orm-4.3.8.RELEASE.jar!/:4.3.8.RELEASE]
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:488) ~[spring-orm-4.3.8.RELEASE.jar!/:4.3.8.RELEASE]
at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:59) ~[spring-tx-4.3.8.RELEASE.jar!/:4.3.8.RELEASE]
at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:213) ~[spring-tx-4.3.8.RELEASE.jar!/:4.3.8.RELEASE]
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:147) ~[spring-tx-4.3.8.RELEASE.jar!/:4.3.8.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.8.RELEASE.jar!/:4.3.8.RELEASE]
at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:133) ~[spring-data-jpa-1.11.3.RELEASE.jar!/:?]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.8.RELEASE.jar!/:4.3.8.RELEASE]
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92) ~[spring-aop-4.3.8.RELEASE.jar!/:4.3.8.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.8.RELEASE.jar!/:4.3.8.RELEASE]
at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:57) ~[spring-data-commons-1.13.3.RELEASE.jar!/:?]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.8.RELEASE.jar!/:4.3.8.RELEASE]
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213) ~[spring-aop-4.3.8.RELEASE.jar!/:4.3.8.RELEASE]
at com.sun.proxy.$Proxy201.getSomeObject(Unknown Source) ~[?:?]
at mypackage.getSomeObject(MyClass.java:111) ~[]
I've been banging my head against the wall for few weeks now trying to fix this issue, but I can't figure out why this exception EntityNotFoundException is thrown.
The exception is ofc correct, I don't understand why it does not return null as usual.
UPD:
public class SomeObject {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
}
Upvotes: 1
Views: 1747
Reputation: 10931
As established in the comments, there is a second-level cache (EhCache?) enabled.
This has the effect that in the example in the question, instance(2) thinks it remembers the create request when the second retrieval comes in, but is then surprised to not find the match in the database.
Upvotes: 1
Reputation: 81998
Not a ready-made complete answer but some instructions on how to debug this kind of thing (and way too long for a comment).
Make sure you have the source code of Spring Data JPA, Spring Data Commons and Spring Data ORM available and properly configured in your IDE.
Get a complete stack trace of the exception you get (not just the part you posted).
Based on the stack trace graciously put breakpoints in the code.
Run the simple scenario that does not throw an exception in the debugger. Keep note which Breakpoint you hit and which you don't.
Remove all breakpoints you hit except the last one. Add more breakpoints between that last one you hit and the first one you missed.
Repeat until these two breakpoints are just one stack frame apart.
Debug through the remaining code between the two breakpoints in both scenarios and observe the differences.
Come back here and tell us what you found either as an update to the question or an answer possibly including a link to an issue and/or pull request.
Upvotes: 0