最近我一直在使用JPA / Hibernate取得了很好的成功,但我仍然遇到了在我的实体中发现错误的麻烦,特别是当错误来自级联持续操作时。
我们使用相当复杂的数据库设计,并且有许多关系,我通常的持久方法包括设置一组实体,分配它们之间的所有链接,然后在根实体上调用persist()
。 / p>
有时会导致SELECT
错误,其中Hibernate抱怨它无法找到给定标识符的实体。
即使Hibernate首先应该INSERT
该实体。
这通常是级联问题,如果我有办法向Hibernate询问它打算执行哪些操作(以及以哪种顺序)来实现persist()
I',它可以很容易地调试问。
如何获取Hibernate持久策略的反馈?
我知道如何请求SQL日志,但这些日志通常非常模糊和冗长,而且根本没有明确说明为什么会有一些SQL命令。
作为一个实际的例子,今天早上我遇到了这种例外:
org.springframework.orm.jpa.JpaObjectRetrievalFailureException: Unable to find foo.bar.product.model.entity.FooEntity with id 113381; nested exception is javax.persistence.EntityNotFoundException: Unable to find foo.bar.product.model.entity.FooEntity with id 113381
at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:389)
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:246)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:491)
at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:59)
at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:213)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:147)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:133)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
at com.sun.proxy.$Proxy88.save(Unknown Source)
at foo.bar.product.model.service.WorkloadService.updateAndSaveAllDependeceWithNewWklId(WorkloadService.java:154)
at foo.bar.product.model.service.WorkloadService$$FastClassBySpringCGLIB$$9cf9789e.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:720)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:280)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:655)
at foo.bar.product.model.service.WorkloadService$$EnhancerBySpringCGLIB$$1e47513d.updateAndSaveAllDependeceWithNewWklId(<generated>)
at foo.bar.product.FooFunction.run(FooFunction.java:137)
at foo.bar.product.FunctionSelectorMain.run(FunctionSelectorMain.java:47)
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:789)
at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:779)
at org.springframework.boot.SpringApplication.afterRefresh(SpringApplication.java:769)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:314)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1185)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1174)
at foo.bar.product.FunctionSelectorMain.main(FunctionSelectorMain.java:29)
Caused by: javax.persistence.EntityNotFoundException: Unable to find foo.bar.product.model.entity.FooEntity with id 113381
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$JpaEntityNotFoundDelegate.handleEntityNotFound(EntityManagerFactoryBuilderImpl.java:144)
at org.hibernate.event.internal.DefaultLoadEventListener.load(DefaultLoadEventListener.java:227)
at org.hibernate.event.internal.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:278)
at org.hibernate.event.internal.DefaultLoadEventListener.doOnLoad(DefaultLoadEventListener.java:121)
at org.hibernate.event.internal.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:89)
at org.hibernate.internal.SessionImpl.fireLoad(SessionImpl.java:1129)
at org.hibernate.internal.SessionImpl.internalLoad(SessionImpl.java:1022)
at org.hibernate.type.EntityType.resolveIdentifier(EntityType.java:632)
at org.hibernate.type.EntityType.resolve(EntityType.java:424)
at org.hibernate.type.EntityType.replace(EntityType.java:323)
at org.hibernate.type.CollectionType.replaceElements(CollectionType.java:518)
at org.hibernate.type.CollectionType.replace(CollectionType.java:663)
at org.hibernate.type.AbstractType.replace(AbstractType.java:147)
at org.hibernate.type.TypeHelper.replaceAssociations(TypeHelper.java:261)
at org.hibernate.event.internal.DefaultMergeEventListener.copyValues(DefaultMergeEventListener.java:427)
at org.hibernate.event.internal.DefaultMergeEventListener.entityIsTransient(DefaultMergeEventListener.java:240)
at org.hibernate.event.internal.DefaultMergeEventListener.entityIsDetached(DefaultMergeEventListener.java:301)
at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:170)
at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:69)
at org.hibernate.internal.SessionImpl.fireMerge(SessionImpl.java:840)
at org.hibernate.internal.SessionImpl.merge(SessionImpl.java:822)
at org.hibernate.internal.SessionImpl.merge(SessionImpl.java:827)
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.merge(AbstractEntityManagerImpl.java:1161)
at sun.reflect.GeneratedMethodAccessor45.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:298)
at com.sun.proxy.$Proxy82.merge(Unknown Source)
at org.springframework.data.jpa.repository.support.SimpleJpaRepository.save(SimpleJpaRepository.java:509)
at org.springframework.data.jpa.repository.support.SimpleJpaRepository.save(SimpleJpaRepository.java:540)
at org.springframework.data.jpa.repository.support.SimpleJpaRepository.save(SimpleJpaRepository.java:72)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.executeMethodOn(RepositoryFactorySupport.java:503)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:488)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:460)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:280)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136)
... 27 more
这里的问题只是在一个与FooEntity相关的实体中缺少持久性级联,但是在没有正确的Hibernate输出的情况下发现其中一个是痛苦的。
答案 0 :(得分:0)
据我所知,你会遇到SQL日志。
由于交易,数据库的持久性是您唯一可以确定数据库中的内容。
当然,您可以通过查看域模型和事务来合理地了解持久性的顺序,但对于复杂的操作,它会变得令人头疼。
答案 1 :(得分:0)
最终我发现Hibernate的类负责级联JPA操作。
一般来说,它足以将org.hibernate.engine.internal.Cascade
的日志级别提高到TRACE
,并显示有用的消息。
该消息将解释每个实体由于级联定义,其他实体将受到哪些操作。
例如,在我写的Spring Boot application.properties
文件中:
logging.level.org.hibernate.engine.internal.Cascade=TRACE
logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.type=TRACE
为了正确调试级联操作及其SQL语句。