简体   繁体   English

Spring数据映射无法按预期工作

[英]Spring Data mapping doesn't work as expected

I have a table option with two foreign keys and many-to-one associations (to tables checkpoint and setting ): db schema . 我有一个带有两个外键和多对一关联(到表检查点设置 )的表选项db schema

From JPA side I have 2 bidirectional associations: with Cascade.ALL and FetchType.EAGER on the one side and Cascade.REMOVE on the second side. 从JPA方面,我有2个双向关联:一侧为Cascade.ALLFetchType.EAGER ,另一侧为Cascade.REMOVE Here is corresponding JPA mappings: 这是对应的JPA映射:

@Entity
@Table(name = "checkpoint")
@AllArgsConstructor
@NoArgsConstructor
@Data
public class Checkpoint {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private long id;

  private long location;

  @OneToMany(mappedBy = "checkpoint",
        cascade = CascadeType.ALL,
        orphanRemoval = true,
        fetch = FetchType.EAGER)
  private List<RewardOption> rewardOptions = new ArrayList<>();
}

@Entity
@Table(name = "setting")
@AllArgsConstructor
@NoArgsConstructor
@Data
public class RewardSetting {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private long id;

  @Column(name = "base_line")
  private long baseLine;

  @OneToMany(mappedBy = "rewardSetting",
        cascade = CascadeType.REMOVE,
        orphanRemoval = true)
  private List<RewardOption> rewardOptions = new ArrayList<>();
}

@Entity
@Table(name = "option")
@AllArgsConstructor
@NoArgsConstructor
@Data
public class RewardOption {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private long id;

  private long weight;

  @ManyToOne
  @JoinColumn(name = "setting_id")
  private RewardSetting rewardSetting;

  @ManyToOne
  @JoinColumn(name = "checkpoint_id")
  private Checkpoint checkpoint;
} 

Also I'm using Spring Data for entity manipulations. 我也使用Spring Data进行实体操作。 To me it seemed as working example, but on practice when I perform: 在我看来,这似乎是一个可行的例子,但是在我练习时却表现出:

...
rewardSettingRepository.delete(rewardSetting);

Or: 要么:

...
rewardSettingRepository.delete(id);

I got JPA tries to remove a row from setting table BEFORE corresponding rows from a option table. 我得到了JPA尝试从选项表中的相应行之前删除设置表中的行。

Does anyone have some ideas why it behaves this way? 有谁知道为什么它会这样运作? Why this mapping leads to this behaviour? 为什么这种映射会导致这种行为? How to do this right way? 如何以正确的方式做?

The full stack trace is: 完整的堆栈跟踪为:

org.springframework.dao.DataIntegrityViolationException: could not execute statement; org.springframework.dao.DataIntegrityViolationException:无法执行语句; SQL [n/a]; SQL [n / a]; constraint [null]; 约束[null]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:278) at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:244) at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:521) at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:765) at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:734) at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:518) at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:292) at org.springframework.transac 嵌套的异常是org.hibernate.exception.ConstraintViolationException:无法在org.springframework.orm.jpa.vendors.HibernateJlateDate处的org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:278)处执行语句。 (HibernateJpaDialect.java:244)在org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:521)在org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:765)在org.springframework。 org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:518)上的transaction.support.AbstractPlatformTransactionManager.java:734)在org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction( 292)在org.springframework.transac tion.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) 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.data.repository.core.support.Surrou org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)上的tion.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)在org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java: 136)at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor $ CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostwork atjava。 org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)上的.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)在org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation。 :179),网址为org.springframework.data.repository.core.support.Surrou ndingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:57) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213) at com.sun.proxy.$Proxy82.delete(Unknown Source) at com.github.star67.hibernatefetchcascade.HibernateFetchCascadeApplication.testSettingDelete(HibernateFetchCascadeApplication.java:41) at com.github.star67.hibernatefetchcascade.HibernateFetchCascadeApplication.main(HibernateFetchCascadeApplication.java:36) org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)的ndingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:57)在org.springframework.aop.framework.JdkDynamicAopProxy.com上的org.springframework.aop.framework.JdkDynamicAopProxy.com com.github.star67.hibernatefetchcascade.HibernateFetchCascadeApplication.testSettingDelete(HibernateFetchCascadeApplication.java:41)上的.sun.proxy。$ Proxy82.delete(未知源),com.github.star67.hibernatefetchcascade.HibernateFetchCascadeApplication.main(HibernateFetchCascadeApplication36。 )

Caused by: org.hibernate.exception.ConstraintViolationException: could not execute statement at org.hibernate.exception.internal.SQLExceptionTypeDelegate.convert(SQLExceptionTypeDelegate.java:59) at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:42) at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:109) at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:95) at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:207) at org.hibernate.engine.jdbc.batch.internal.NonBatchingBatch.addToBatch(NonBatchingBatch.java:45) at org.hibernate.persister.entity.AbstractEntityPersister.delete(AbstractEntityPersister.java:3261) at org.hibernate.persister.entity.AbstractEntityPersister.delete(AbstractEntityPersister.java:3498) at org.hibernate.action.internal.EntityDeleteAction.execute(EntityDeleteAction.java:98) at org.hibernate.engine.sp 引起原因:org.hibernate.exception.ConstraintViolationException:无法在org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java)的org.hibernate.exception.internal.SQLExceptionTypeDelegate.convert(SQLExceptionTypeDelegate.java:59)处执行语句:42)在org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:109)在org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:95)在org.hibernate。 org.hibernate.engine.jdbc.batch.internal.NonBatchingBatch.addToBatch(NonBatchingBatch.java:45)处的engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:207)在org.hibernate.persister.entity.AbstractEntityPersister。在org.hibernate.org.hibernate.persister.entity.AbstractEntityPersister.delete(AbstractEntityPersister.java:3498)处org.hibernate.action.internal.EntityDeleteAction.execute(EntityDeleteAction.java:98)处delete(AbstractEntityPersister.java:3261) .engine.sp i.ActionQueue.executeActions(ActionQueue.java:582) at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:456) at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:337) at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:39) at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1282) at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:465) at org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:2963) at org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:2339) at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:485) at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.beforeCompletionCallback(JdbcResourceLocalTransactionCoordinatorImpl.java:147) at org.hibernate.resource.tra i.ActionQueue.executeActions(ActionQueue.java:582)位于org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:456)位于org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:337)在org.hibernate.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:39)在org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1282)在org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java) :465),位于org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:2963),位于org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:2339),位于org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl。 org.hibernate.resource.org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.beforeCompletionCallback(JdbcResourceLocalTransactionCoordinatorImpl.java:147)处的beforeTransactionCompletion(JdbcCoordinatorImpl.java:485) nsaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.access$100(JdbcResourceLocalTransactionCoordinatorImpl.java:38) at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commit(JdbcResourceLocalTransactionCoordinatorImpl.java:231) at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:65) at org.hibernate.jpa.internal.TransactionImpl.commit(TransactionImpl.java:61) at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:517) ... 18 more nsaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.access $ 100(JdbcResourceLocalTransactionCoordinatorImpl.java:38)at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl $ Transaction。 org.hibernate.jpa.internal.TransactionImpl.commit(TransactionImpl.java:61)上的.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:65)org.springframework.orm.jpa.Jpa.JpaTransactionManager.doCommit(JpaTransactionManager .java:517)...还有18个

Caused by: java.sql.SQLIntegrityConstraintViolationException: Cannot delete or update a parent row: a foreign key constraint fails ( demo . option , CONSTRAINT FKdhs5wopt13o6b9gl4wydr0l9o FOREIGN KEY ( setting_id ) REFERENCES setting ( id )) at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:115) at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:95) at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122) at com.mysql.cj.jdbc.ClientPreparedStatement.executeInternal(ClientPreparedStatement.java:960) at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdateInternal(ClientPreparedStatement.java:1116) at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdateInternal(ClientPreparedStatement.java:1066) at com.mysql.cj.jdbc.ClientPreparedStatement.executeLargeUpdate(ClientPreparedStatement.java:1396) at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdate(ClientPreparedStatement.java:1051) at sun java.sql.SQLIntegrityConstraintViolationException:由造成无法删除或更新父行,外键约束失败( demooption ,约束FKdhs5wopt13o6b9gl4wydr0l9o外键( setting_id )参考settingid ))在com.mysql.cj.jdbc.exceptions com.mysql.cj.jdbc.exceptions上的.SQLError.createSQLException(SQLError.java:115)。com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java上的.SQLError.createSQLException(SQLError.java:95) :com.mysql.cj.jdbc.ClientPreparedStatement.executeInternal(ClientPreparedStatement.java:960)处com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdateInternal(ClientPreparedStatement.java:1116)处com.mysql.cj.jdbc。在com.mysql.cj.jdbc.ClientPreparedStatement.executeLargeUpdate(ClientPreparedStatement.java:1396)处的ClientPreparedStatement.executeUpdateInternal(ClientPreparedStatement.java:1066)在com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdate(ClientPreparedStatementjava: .reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.apache.tomcat.jdbc.pool.StatementFacade$StatementProxy.invoke(StatementFacade.java:114) at com.sun.proxy.$Proxy89.executeUpdate(Unknown Source) at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:204) ... 37 more .reflect.NativeMethodAccessorImpl.invoke0(本机方法)位于sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)在sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)在java.lang.reflect.Method.invoke (Method.java:498),位于org.apache.tomcat.jdbc.pool.StatementFacade $ StatementProxy.invoke(StatementFacade.java:114),位于com.sun.proxy。$ Proxy89.executeUpdate(未知源),位于org.hibernate。 engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:204)...更多37

Also, after playing around I found some strange things, that I cannot explain: 此外,在玩耍之后,我发现了一些奇怪的东西,我无法解释:

  1. Adding @ManyToOne(fetch = FetchType.LAZY) for Checkpoint in the class RewardOption fixes the problem, but how fetch type influences cascade? RewardOption类中为Checkpoint添加@ManyToOne(fetch = FetchType.LAZY) 可解决此问题,但是访类型如何影响级联?
  2. Changing cascade = CascadeType.ALL to cascade = CascadeType.REMOVE in the class Checkpoint fixes the problem but I need ability to save cascade... Checkpoint类中的层叠= CascadeType.ALL更改为层叠= CascadeType.REMOVE可以解决此问题,但我需要能够保存层叠...

If anyone could throw some light on these "fixes" it would be great. 如果有人可以对这些“修补程序”有所了解,那就太好了。

Here is the code to play around 这是要玩的代码

To make it work, you need to synchronize both end of the bidirectional association . 为了使其正常工作,您需要同步双向关联的两端

That means, prior to calling delete, you need to make sure you disassociate the parent from al child entities. 这意味着,在调用delete之前,您需要确保将父级与所有子级实体解除关联。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM