JpaRepository 抛出 EntityNotFoundException 而不是返回 null
JpaRepository throwing EntityNotFoundException instead of returning null
我遇到了这个非常不寻常的错误。
我有这个 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);
}
它工作正常,当我尝试获取 ID 不存在的 SomeObject 时,它只是 return 为空,我处理它并继续进行。
但是,当我引入我的应用程序的多个实例(比如 2 个),并将它们隐藏在负载均衡器后面时。我执行此操作(作为脚本),其中 retrieves/creates/deletes SomeObject 重复。
当我只有一个实例时,我 运行 执行以下操作的脚本:检索 (returns null) -> 创建 SomeObject,删除 SomeObject 并重复检索 (returns null) -> ...等
一切正常,符合预期^
在我的多实例设置中,负载均衡器将请求重新路由到可互换的实例。
意思是,操作现在按以下顺序进行:
实例(1)检索(returns null)
实例(2)创建SomeObject
实例(1)删除SomeObject
并且在下一次迭代中,观察到一些奇怪的行为!
实例(2)检索(这里不是returning null,Spring突然抛出以下异常):
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) ~[]
几周来我一直在用头撞墙试图解决这个问题,但我不明白为什么会抛出这个异常 EntityNotFoundException。
异常是正确的,我不明白为什么它不像往常一样 return null。
更新:
public class SomeObject {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
}
不是现成的完整答案,而是一些关于如何调试此类问题的说明(对于评论来说太长了)。
确保您拥有 Spring Data JPA、Spring Data Commons 和 Spring Data ORM 的源代码并在 [=47] 中正确配置=].
获取您遇到的异常的完整堆栈跟踪(不仅仅是您发布的部分)。
根据堆栈跟踪,优雅地在代码中放置断点。
运行调试器不抛出异常的简单场景。记下你命中了哪个断点,没有命中哪个断点。
删除除最后一个以外的所有断点。在您命中的最后一个和错过的第一个之间添加更多断点。
重复直到这两个断点仅相隔一个堆栈帧。
调试两个场景下两个断点之间的剩余代码,观察差异。
回到这里,告诉我们您发现了什么,作为问题的更新或答案可能包括 link 问题 and/or 拉取请求。
如评论中所述,启用了二级缓存(EhCache?)。
这有这样的效果,在问题的例子中,instance(2) 认为它在第二次检索进来时记住了创建请求,但随后惊讶地没有在数据库中找到匹配项。
我遇到了这个非常不寻常的错误。
我有这个 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);
}
它工作正常,当我尝试获取 ID 不存在的 SomeObject 时,它只是 return 为空,我处理它并继续进行。
但是,当我引入我的应用程序的多个实例(比如 2 个),并将它们隐藏在负载均衡器后面时。我执行此操作(作为脚本),其中 retrieves/creates/deletes SomeObject 重复。
当我只有一个实例时,我 运行 执行以下操作的脚本:检索 (returns null) -> 创建 SomeObject,删除 SomeObject 并重复检索 (returns null) -> ...等
一切正常,符合预期^
在我的多实例设置中,负载均衡器将请求重新路由到可互换的实例。 意思是,操作现在按以下顺序进行:
实例(1)检索(returns null)
实例(2)创建SomeObject
实例(1)删除SomeObject
并且在下一次迭代中,观察到一些奇怪的行为!
实例(2)检索(这里不是returning null,Spring突然抛出以下异常):
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) ~[]
几周来我一直在用头撞墙试图解决这个问题,但我不明白为什么会抛出这个异常 EntityNotFoundException。
异常是正确的,我不明白为什么它不像往常一样 return null。
更新:
public class SomeObject {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
}
不是现成的完整答案,而是一些关于如何调试此类问题的说明(对于评论来说太长了)。
确保您拥有 Spring Data JPA、Spring Data Commons 和 Spring Data ORM 的源代码并在 [=47] 中正确配置=].
获取您遇到的异常的完整堆栈跟踪(不仅仅是您发布的部分)。
根据堆栈跟踪,优雅地在代码中放置断点。
运行调试器不抛出异常的简单场景。记下你命中了哪个断点,没有命中哪个断点。
删除除最后一个以外的所有断点。在您命中的最后一个和错过的第一个之间添加更多断点。
重复直到这两个断点仅相隔一个堆栈帧。
调试两个场景下两个断点之间的剩余代码,观察差异。
回到这里,告诉我们您发现了什么,作为问题的更新或答案可能包括 link 问题 and/or 拉取请求。
如评论中所述,启用了二级缓存(EhCache?)。
这有这样的效果,在问题的例子中,instance(2) 认为它在第二次检索进来时记住了创建请求,但随后惊讶地没有在数据库中找到匹配项。