Spring数据映射无法正常工作

时间:2018-07-29 15:20:44

标签: java jpa spring-data-jpa

我有一个表选项,该表带有两个外键和多对一关联(到表检查点设置):{{ 3}}。

从JPA角度来看,我有2个双向关联:一侧是 Cascade.ALL FetchType.EAGER ,另一侧是 Cascade.REMOVE 第二面。这是对应的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;
} 

我也正在使用Spring Data进行实体操作。对我来说,这似乎是一个可行的例子,但是在我练习时却表现出来:

...
rewardSettingRepository.delete(rewardSetting);

或者:

...
rewardSettingRepository.delete(id);

我让JPA尝试从 option 表的 setting 之前对应的行中删除一行。

有人知道为什么会这样吗? 为什么这种映射会导致这种行为? 如何以正确的方式做事?

完整的堆栈跟踪为:

  

org.springframework.dao.DataIntegrityViolationException:无法执行语句; SQL [n / a];约束[null];嵌套的异常是org.hibernate.exception.ConstraintViolationException:无法执行语句       在org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:278)       在org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:244)       在org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:521)       在org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:765)       在org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:734)       在org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:518)       在org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:292)       在org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)       在org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)       在org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136)       在org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)       在org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor $ CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:133)处       在org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)       在org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)       在org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)       在org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:57)       在org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)       在org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)       在com.sun.proxy。$ Proxy82.delete(未知来源)       在com.github.star67.hibernatefetchcascade.HibernateFetchCascadeApplication.testSettingDelete(HibernateFetchCascadeApplication.java:41)       在com.github.star67.hibernatefetchcascade.HibernateFetchCascadeApplication.main(HibernateFetchCascadeApplication.java:36)

     

由以下原因引起:org.hibernate.exception.ConstraintViolationException:无法执行语句       在org.hibernate.exception.internal.SQLExceptionTypeDelegate.convert(SQLExceptionTypeDelegate.java:59)       在org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:42)       在org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:109)       在org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:95)       在org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:207)       在org.hibernate.engine.jdbc.batch.internal.NonBatchingBatch.addToBatch(NonBatchingBatch.java:45)       在org.hibernate.persister.entity.AbstractEntityPersister.delete(AbstractEntityPersister.java:3261)       在org.hibernate.persister.entity.AbstractEntityPersister.delete(AbstractEntityPersister.java:3498)       在org.hibernate.action.internal.EntityDeleteAction.execute(EntityDeleteAction.java:98)       在org.hibernate.engine.spi.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.event.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.beforeTransactionCompletion(JdbcCoordinatorImpl.java:485)处       在org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.beforeCompletionCallback(JdbcResourceLocalTransactionCoordinatorImpl.java:147)       在org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.access $ 100(JdbcResourceLocalTransactionCoordinatorImpl.java:38)       在org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl $ TransactionDriverControlImpl.commit(JdbcResourceLocalTransactionCoordinatorImpl.java:231)处       在org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:65)       在org.hibernate.jpa.internal.TransactionImpl.commit(TransactionImpl.java:61)       在org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:517)       ...另外18个

     

由以下原因引起:java.sql.SQLIntegrityConstraintViolationException:无法删除或更新父行:外键约束失败(demooption,CONSTRAINT FKdhs5wopt13o6b9gl4wydr0l9o FOREIGN KEY({{1 }})参考文献setting_idsetting))       在com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:115)       在com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:95)       在com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122)       在com.mysql.cj.jdbc.ClientPreparedStatement.executeInternal(ClientPreparedStatement.java:960)       在com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdateInternal(ClientPreparedStatement.java:1116)       在com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdateInternal(ClientPreparedStatement.java:1066)       在com.mysql.cj.jdbc.ClientPreparedStatement.executeLargeUpdate(ClientPreparedStatement.java:1396)       在com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdate(ClientPreparedStatement.java:1051)       在sun.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

此外,在玩耍之后,我发现了一些奇怪的东西,我无法解释:

  1. RewardOption 类中为 Checkpoint 添加 @ManyToOne(fetch = FetchType.LAZY)可以解决此问题,但是获取类型如何影响级联?
  2. Checkpoint 类中将 cascade = CascadeType.ALL 更改为 cascade = CascadeType.REMOVE 可以解决此问题,但我需要能够保存级联的功能...

如果有人可以对这些“修补程序”有所了解,那就太好了。

db schema

1 个答案:

答案 0 :(得分:0)

要使其正常运行,您需要synchronize both end of the bidirectional association

这意味着,在调用delete之前,您需要确保将父级与所有子级实体解除关联。