即使级联为 ALL,Hibernate 也无法持续存在

Posted

技术标签:

【中文标题】即使级联为 ALL,Hibernate 也无法持续存在【英文标题】:Hibernate fails to persist even when cascade is ALL 【发布时间】:2019-01-09 11:41:32 【问题描述】:

我在 Wildfly EE 项目中有两个实体 AuthorizationPositionProductAttributes。两者的映射如下:

授权位置:

  @javax.persistence.ManyToOne(fetch =  javax.persistence.FetchType.LAZY , optional=false, cascade = javax.persistence.CascadeType.ALL)
  @javax.persistence.JoinColumn(name = "PRODUCT_ATTRIBUTES_ID", referencedColumnName="PRODUCT_ATTRIBUTES_ID")
  protected org.example.persistence.entity.ProductAttributes productAttributes;

产品属性:

  @javax.persistence.OneToMany(
        targetEntity=org.example.persistence.entity.AuthorizationPosition.class,
        mappedBy="productAttributes",
        fetch=javax.persistence.FetchType.LAZY
                    , cascade = javax.persistence.CascadeType.ALL
                 , orphanRemoval = true         )
  protected java.util.Set<org.example.persistence.entity.AuthorizationPosition> authorizationPositionsByProductAttributes;

我在两个实体中设置了所有关系并在ProductAttributes 上调用em.persist()(作为更大结构的一部分)这是出现奇怪错误的地方(问题末尾的完整堆栈跟踪):

java.lang.IllegalStateException: org.hibernate.TransientPropertyValueException: Not-null property references a transient value - transient instance must be saved before current operation : org.example.persistence.entity.AuthorizationPosition.productAttributes -> org.example.persistence.entity.ProductAttributes

是我遗漏了什么还是 Hibernate (hibernate-core-5.3.1.Final) 真的试图以另一种方式坚持?尽管CascadeType.ALL 存在于所有关系映射中,这不应该是个问题吗?

完整的堆栈跟踪:

java.lang.IllegalStateException: org.hibernate.TransientPropertyValueException: Not-null property references a transient value - transient instance must be saved before current operation : org.example.persistence.entity.AuthorizationPosition.productAttributes -> org.example.persistence.entity.ProductAttributes
    at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:146) [hibernate-core-5.3.1.Final.jar:5.3.1.Final]
    at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:157) [hibernate-core-5.3.1.Final.jar:5.3.1.Final]
    at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:164) [hibernate-core-5.3.1.Final.jar:5.3.1.Final]
    at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:814) [hibernate-core-5.3.1.Final.jar:5.3.1.Final]
    at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:785) [hibernate-core-5.3.1.Final.jar:5.3.1.Final]
    at org.jboss.as.jpa.container.AbstractEntityManager.persist(AbstractEntityManager.java:580) [wildfly-jpa-13.0.0.Final.jar:13.0.0.Final]
    at org.example.control.ImportServoceImpl.import(ImportServoceImpl.java:109) [service-SNAPSHOT.jar:]
    at org.example.rest.control.ImportContainerService.importDocument(ImportContainerService.java:65) [classes:]
    at org.example.rest.control.ImportContainerService$Proxy$_$$_WeldSubclass.importDocument$$super(Unknown Source) [classes:]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) [rt.jar:1.8.0_191]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) [rt.jar:1.8.0_191]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) [rt.jar:1.8.0_191]
    at java.lang.reflect.Method.invoke(Method.java:498) [rt.jar:1.8.0_191]
    at org.jboss.weld.interceptor.proxy.TerminalAroundInvokeInvocationContext.proceedInternal(TerminalAroundInvokeInvocationContext.java:51) [weld-core-impl-3.0.4.Final.jar:3.0.4.Final]
    at org.jboss.weld.interceptor.proxy.AroundInvokeInvocationContext.proceed(AroundInvokeInvocationContext.java:78) [weld-core-impl-3.0.4.Final.jar:3.0.4.Final]
    at org.hibernate.validator.cdi.internal.interceptor.ValidationInterceptor.validateMethodInvocation(ValidationInterceptor.java:79) [hibernate-validator-cdi-6.0.10.Final.jar:6.0.10.Final]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) [rt.jar:1.8.0_191]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) [rt.jar:1.8.0_191]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) [rt.jar:1.8.0_191]
    at java.lang.reflect.Method.invoke(Method.java:498) [rt.jar:1.8.0_191]
    at org.jboss.weld.interceptor.reader.SimpleInterceptorInvocation$SimpleMethodInvocation.invoke(SimpleInterceptorInvocation.java:73) [weld-core-impl-3.0.4.Final.jar:3.0.4.Final]
    at org.jboss.weld.interceptor.proxy.InterceptorMethodHandler.executeAroundInvoke(InterceptorMethodHandler.java:84) [weld-core-impl-3.0.4.Final.jar:3.0.4.Final]
    at org.jboss.weld.interceptor.proxy.InterceptorMethodHandler.executeInterception(InterceptorMethodHandler.java:72) [weld-core-impl-3.0.4.Final.jar:3.0.4.Final]
    at org.jboss.weld.interceptor.proxy.InterceptorMethodHandler.invoke(InterceptorMethodHandler.java:56) [weld-core-impl-3.0.4.Final.jar:3.0.4.Final]
    at org.jboss.weld.bean.proxy.CombinedInterceptorAndDecoratorStackMethodHandler.invoke(CombinedInterceptorAndDecoratorStackMethodHandler.java:79) [weld-core-impl-3.0.4.Final.jar:3.0.4.Final]
    at org.jboss.weld.bean.proxy.CombinedInterceptorAndDecoratorStackMethodHandler.invoke(CombinedInterceptorAndDecoratorStackMethodHandler.java:68) [weld-core-impl-3.0.4.Final.jar:3.0.4.Final]
    at org.example.rest.control.ImportContainerService$Proxy$_$$_WeldSubclass.importDocument(Unknown Source) [classes:]
    at org.example.rest.boundary.ContainerRestService.import(ContainerRestService.java:181) [classes:]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) [rt.jar:1.8.0_191]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) [rt.jar:1.8.0_191]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) [rt.jar:1.8.0_191]
    at java.lang.reflect.Method.invoke(Method.java:498) [rt.jar:1.8.0_191]
    at org.jboss.as.ee.component.ManagedReferenceMethodInterceptor.processInvocation(ManagedReferenceMethodInterceptor.java:52)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
    at org.jboss.invocation.InterceptorContext$Invocation.proceed(InterceptorContext.java:509)
    at org.jboss.as.weld.ejb.DelegatingInterceptorInvocationContext.proceed(DelegatingInterceptorInvocationContext.java:92) [wildfly-weld-ejb-13.0.0.Final.jar:13.0.0.Final]
    at org.jboss.weld.interceptor.proxy.WeldInvocationContextImpl.interceptorChainCompleted(WeldInvocationContextImpl.java:107) [weld-core-impl-3.0.4.Final.jar:3.0.4.Final]
    at org.jboss.weld.interceptor.proxy.WeldInvocationContextImpl.proceed(WeldInvocationContextImpl.java:126) [weld-core-impl-3.0.4.Final.jar:3.0.4.Final]
    at org.hibernate.validator.cdi.internal.interceptor.ValidationInterceptor.validateMethodInvocation(ValidationInterceptor.java:79) [hibernate-validator-cdi-6.0.10.Final.jar:6.0.10.Final]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) [rt.jar:1.8.0_191]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) [rt.jar:1.8.0_191]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) [rt.jar:1.8.0_191]
    at java.lang.reflect.Method.invoke(Method.java:498) [rt.jar:1.8.0_191]
    at org.jboss.weld.interceptor.reader.SimpleInterceptorInvocation$SimpleMethodInvocation.invoke(SimpleInterceptorInvocation.java:73) [weld-core-impl-3.0.4.Final.jar:3.0.4.Final]
    at org.jboss.weld.interceptor.proxy.WeldInvocationContextImpl.invokeNext(WeldInvocationContextImpl.java:92) [weld-core-impl-3.0.4.Final.jar:3.0.4.Final]
    at org.jboss.weld.interceptor.proxy.WeldInvocationContextImpl.proceed(WeldInvocationContextImpl.java:124) [weld-core-impl-3.0.4.Final.jar:3.0.4.Final]
    at org.jboss.weld.bean.InterceptorImpl.intercept(InterceptorImpl.java:105) [weld-core-impl-3.0.4.Final.jar:3.0.4.Final]
    at org.jboss.as.weld.ejb.DelegatingInterceptorInvocationContext.proceed(DelegatingInterceptorInvocationContext.java:82) [wildfly-weld-ejb-13.0.0.Final.jar:13.0.0.Final]
    at org.jboss.as.weld.interceptors.EjbComponentInterceptorSupport.delegateInterception(EjbComponentInterceptorSupport.java:60)
    at org.jboss.as.weld.interceptors.Jsr299BindingsInterceptor.delegateInterception(Jsr299BindingsInterceptor.java:76)
    at org.jboss.as.weld.interceptors.Jsr299BindingsInterceptor.doMethodInterception(Jsr299BindingsInterceptor.java:88)
    at org.jboss.as.weld.interceptors.Jsr299BindingsInterceptor.processInvocation(Jsr299BindingsInterceptor.java:101)
    at org.jboss.as.ee.component.interceptors.UserInterceptorFactory$1.processInvocation(UserInterceptorFactory.java:63)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
    at org.jboss.as.ejb3.component.invocationmetrics.ExecutionTimeInterceptor.processInvocation(ExecutionTimeInterceptor.java:43) [wildfly-ejb3-13.0.0.Final.jar:13.0.0.Final]
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
    at org.jboss.as.jpa.interceptor.SBInvocationInterceptor.processInvocation(SBInvocationInterceptor.java:47) [wildfly-jpa-13.0.0.Final.jar:13.0.0.Final]
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
    at org.jboss.as.ee.concurrent.ConcurrentContextInterceptor.processInvocation(ConcurrentContextInterceptor.java:45) [wildfly-ee-13.0.0.Final.jar:13.0.0.Final]
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
    at org.jboss.invocation.InitialInterceptor.processInvocation(InitialInterceptor.java:40)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
    at org.jboss.invocation.ChainedInterceptor.processInvocation(ChainedInterceptor.java:53)
    at org.jboss.as.ee.component.interceptors.ComponentDispatcherInterceptor.processInvocation(ComponentDispatcherInterceptor.java:52)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
    at org.jboss.as.ejb3.component.pool.PooledInstanceInterceptor.processInvocation(PooledInstanceInterceptor.java:51) [wildfly-ejb3-13.0.0.Final.jar:13.0.0.Final]
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
    at org.jboss.as.ejb3.tx.CMTTxInterceptor.invokeInOurTx(CMTTxInterceptor.java:237) [wildfly-ejb3-13.0.0.Final.jar:13.0.0.Final]
    ... 104 more
Caused by: org.hibernate.TransientPropertyValueException: Not-null property references a transient value - transient instance must be saved before current operation : org.example.persistence.entity.AuthorizationPosition.productAttributes -> org.example.persistence.entity.ProductAttributes
    at org.hibernate.action.internal.UnresolvedEntityInsertActions.checkNoUnresolvedActionsAfterOperation(UnresolvedEntityInsertActions.java:122) [hibernate-core-5.3.1.Final.jar:5.3.1.Final]
    at org.hibernate.engine.spi.ActionQueue.checkNoUnresolvedActionsAfterOperation(ActionQueue.java:436) [hibernate-core-5.3.1.Final.jar:5.3.1.Final]
    at org.hibernate.internal.SessionImpl.checkNoUnresolvedActionsAfterOperation(SessionImpl.java:648) [hibernate-core-5.3.1.Final.jar:5.3.1.Final]
    at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:811) [hibernate-core-5.3.1.Final.jar:5.3.1.Final]
    ... 168 more

持久性单元属性:

   <properties>
        <property name="hibernate.dialect" value="org.hibernate.dialect.Oracle10gDialect"/>
        <property name="hibernate.connection.isolation" value="READ_COMMITTED"/>
        <property name="hibernate.listeners.envers.autoRegister" value="false"/>
        <!--<property name="hibernate.globally_quoted_identifiers" value="true"/>-->
        <!-- note: no DDL validation, because it kicks in before Liquibase gets a chance to update the schema
        <property name="hibernate.hbm2ddl.auto" value="validate"/>
        -->

        <!-- hibernate version integrated in Wildfly states:
        Legacy Hibernate behavior was to ignore the @DiscriminatorColumn.
        However, as part of issue HHH-6911 we now apply the explicit @DiscriminatorColumn.
        If you would prefer the legacy behavior, enable the `hibernate.discriminator.ignore_explicit_for_joined`
        setting (hibernate.discriminator.ignore_explicit_for_joined=true) -->
        <property name="hibernate.discriminator.ignore_explicit_for_joined" value="true"/>

        <property name="hibernate.enhancer.enableDirtyTracking" value="true"/>
        <property name="hibernate.enhancer.enableLazyInitialization" value="false"/>
        <property name="hibernate.enhancer.enableAssociationManagement" value="false"/>
        <property name="hibernate.bytecode.use_reflection_optimizer" value="true"/>

        <property name="hibernate.show_sql" value="$hibernate.showsql"/>
        <property name="hibernate.format_sql" value="true"/>
        <property name="hibernate.use_sql_comments" value="true"/>

        <property name="hibernate.cache.use_second_level_cache" value="true"/>
        <property name="hibernate.cache.use_query_cache" value="true"/>
        <property name="hibernate.cache.use_minimal_puts" value="true"/>
        <property name="hibernate.cache.use_structured_entries" value="true"/>

        <property name="hibernate.default_batch_fetch_size" value="64"/>
        <property name="hibernate.jdbc.batch_size" value="100"/>
        <property name="hibernate.jdbc.fetch_size" value="100"/>
        <property name="hibernate.jdbc.batch_versioned_data" value="false"/>
        <property name="hibernate.order_inserts" value="true"/>
        <property name="hibernate.order_updates" value="true"/>

        <property name="hibernate.generate_statistics" value="false"/>

        <property name="hibernate.connection.useUnicode" value="true"/>
        <property name="hibernate.connection.characterEncoding" value="UTF-8"/>
        <property name="hibernate.jdbc.time_zone" value="UTC"/>
    </properties>

编辑1:

我在两个实体上都设置了关系。我使用与以下类似的代码(为清楚起见,删除了某些部分):

public void addAuthorizationPositionByProductAttributes(@NotNull AuthorizationPosition authorizationPositionByProductAttributes) 
   if(this.authorizationPositionsByProductAttributes.add(authorizationPositionByProductAttributes))
      authorizationPositionByProductAttributes.setProductAttributes(this);
   

当我在调试中检查它时,值设置正确。

【问题讨论】:

你能展示你在持久化之前是如何设置实体的吗? 嗨,也许您可​​以从 ProductAttributes -> AuthorizationPosition 链接中删除 Cascade.ALL ?我不确定这是否能解决问题,但我认为这可能会导致实体“ProductAttributes”被持久化两次 我试过了..映射的原始状态是没有那个:/ 我错过了什么? link 因为这行得通 @xerx593 这是级联应该做的。问题是为什么级联不起作用... 【参考方案1】:

我有点惊讶。我们尝试了所有建议:

@mrtna remove Cascade.ALL from the ProductAttributes -&gt; AuthorizationPosition @JonathanJohx remove orphanRemoval = true , referencedColumnName="PRODUCT_ATTRIBUTES_ID") optional=false, @TiMr remove optional and add nullable=false to the join column and change lazy to Eager @alekz same AuthorizationPosition entity is added to two ProductAttributes?

但似乎没有任何效果,一些导致空约束验证问题 (ORA-01400) 其他人的行为完全相同。

在测试性能时,我们在persistence.xml 中完全禁用了验证(用于比较测试):

<validation-mode>NONE</validation-mode>

并且由于意外点击错误的文件上传 - 令我惊讶的是 - 结构保持良好,没有任何错误或违反约束......

TL.DR.:这是验证器中的一个休眠错误,它阻止了我们坚持。如果validation-mode 设置为NONE,则结构将保持不变。我们现在检查em.persist(..) 调用之前的验证信息并相应地评估结果。

【讨论】:

【参考方案2】:

您是否尝试从 AuthorizationPosition 中删除 optional=false

有时,Hibernate 无法将事物按“正确”的顺序排列。

Hibernate 有时需要将 NULL 存储在外键中,尽管有一种理论上的方法可以避免它。在这些情况下,您必须删除非空约束。 (我从外键中删除了所有非空约束...)

您可以尝试从AuthorizationPosition 中删除级联,这可能是导致排序问题的原因。但我想这不会改变任何事情。

【讨论】:

以上是关于即使级联为 ALL,Hibernate 也无法持续存在的主要内容,如果未能解决你的问题,请参考以下文章

Hibernate级联操作

Hibernate5-1对多(1:n)-级联删除-cascade="all"

2018.11.4 Hibernate中多对多的关系

hibernate初步2

Hibernate中cascade属性的区别

hibernate级联配置