hibernate - 无法删除或更新父行:从具有 2 个子级的中间父级删除条目时,外键约束失败
问题描述
我将首先指定我的实体,以便你们清楚地了解我的要求。这是非常必要的,所以请多多包涵。
我有 4 个实体:
Employee
(很好 - 家长)EmployeeEmail
(中间父级, 的子级Employee
)EmployeeMails
(的孩子EmployeeEmail
)EmployeeAttachments
(的孩子EmployeeEmail
)
当我从 Great - Parent,Employee
中删除一个条目时,所有其他 3 个子实体中的相关子条目将被自动删除。它完美地工作。
但是,当我尝试从中间父级(即 )中删除记录时EmployeeEmail
,我收到错误消息:java.sql.SQLIntegrityConstraintViolationException: Cannot delete or update a parent row: a foreign key constraint fails
. 即使父母双方的代码结构相同,也会发生这种情况,并且我希望即使从 中删除条目EmployeeEmail
,也只会自动删除该条目及其所有子条目,并保留其中的任何相关条目,Employee (Great - Parent)
这就是问题所在。我该如何解决这个问题?
这是我的实体代码:(错误堆栈跟踪在本节之后)
雇员.java
package core.gourabix.entities;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import com.fasterxml.jackson.annotation.JsonIgnore;
@Entity
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int employeeId;
@Column(nullable = false, updatable = true)
private String name;
@JsonIgnore
@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "employee")
private List<EmployeeEmail> personalEmails = new ArrayList<EmployeeEmail>();
public int getEmployeeId() {
return employeeId;
}
public void setEmployeeId(int employeeId) {
this.employeeId = employeeId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<EmployeeEmail> getPersonalEmails() {
return personalEmails;
}
public void setPersonalEmails(List<EmployeeEmail> personalEmails) {
this.personalEmails = personalEmails;
}
public void addEmployeeEmail(EmployeeEmail employeeEmail)
{
employeeEmail.setEmployee(this);
personalEmails.add(employeeEmail);
}
public void removeEmployeeEmail(EmployeeEmail employeeEmail)
{
personalEmails.remove(employeeEmail);
employeeEmail.setEmployee(null);
}
}
EmployeeEmail.java
package core.gourabix.entities;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import com.fasterxml.jackson.annotation.JsonIgnore;
@Entity
public class EmployeeEmail {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int employeeEmailId;
@Column(nullable = false, updatable = true)
private String email;
@ManyToOne
@JoinColumn(name = "employeeId")
private Employee employee;
@JsonIgnore
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true, mappedBy = "employeeEmail")
private List<EmployeeMails> mails; // one email account can store many e-mails.
@JsonIgnore
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true, mappedBy = "employeeEmail")
private List<EmployeeAttachments> attachments; // one email account can store many attachments.
public int getEmployeeEmailId() {
return employeeEmailId;
}
public void setEmployeeEmailId(int employeeEmailId) {
this.employeeEmailId = employeeEmailId;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Employee getEmployee() {
return employee;
}
public void setEmployee(Employee employee) {
this.employee = employee;
}
public List<EmployeeMails> getMails() {
return mails;
}
public void setMails(List<EmployeeMails> mails) {
this.mails = mails;
}
public void addEmployeeMails(EmployeeMails employeeMails)
{
employeeMails.setEmployeeEmail(this);
mails.add(employeeMails);
}
public void removeEmployeeMails(EmployeeMails employeeMails)
{
mails.remove(employeeMails);
employeeMails.setEmployeeEmail(null);
}
public void addEmployeeAttachments(EmployeeAttachments employeeAttachments)
{
employeeAttachments.setEmployeeEmail(this);
attachments.add(employeeAttachments);
}
public void removeEmployeeAttachments(EmployeeAttachments employeeAttachments)
{
attachments.remove(employeeAttachments);
employeeAttachments.setEmployeeEmail(null);
}
}
EmployeeMails.java
package core.gourabix.entities;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
@Entity
public class EmployeeMails {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int mailId;
@Column(nullable = true, updatable = false)
private String mailContent;
@ManyToOne
@JoinColumn(name = "employeeEmailId")
private EmployeeEmail employeeEmail; // many mails belong to one email account.
public int getMailId() {
return mailId;
}
public void setMailId(int mailId) {
this.mailId = mailId;
}
public String getMailContent() {
return mailContent;
}
public void setMailContent(String mailContent) {
this.mailContent = mailContent;
}
public EmployeeEmail getEmployeeEmail() {
return employeeEmail;
}
public void setEmployeeEmail(EmployeeEmail employeeEmail) {
this.employeeEmail = employeeEmail;
}
}
员工附件.java
package core.gourabix.entities;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
@Entity
public class EmployeeAttachments {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int attachmentId;
@Column(nullable = true, updatable = true)
private String attachmentContent;
@ManyToOne
@JoinColumn(name = "employeeEmailId")
private EmployeeEmail employeeEmail;
public int getAttachmentId() {
return attachmentId;
}
public void setAttachmentId(int attachmentId) {
this.attachmentId = attachmentId;
}
public String getAttachmentContent() {
return attachmentContent;
}
public void setAttachmentContent(String attachmentContent) {
this.attachmentContent = attachmentContent;
}
public EmployeeEmail getEmployeeEmail() {
return employeeEmail;
}
public void setEmployeeEmail(EmployeeEmail employeeEmail) {
this.employeeEmail = employeeEmail;
}
}
这是完整的异常堆栈跟踪:
Hibernate: delete from EmployeeEmail where employeeEmailId=?
2019-12-08 01:51:54.540 WARN 2876 --- [nio-8080-exec-9] o.h.engine.jdbc.spi.SqlExceptionHelper : SQL Error: 1451, SQLState: 23000
2019-12-08 01:51:54.540 ERROR 2876 --- [nio-8080-exec-9] o.h.engine.jdbc.spi.SqlExceptionHelper : Cannot delete or update a parent row: a foreign key constraint fails (`parentchildkeyrelations`.`employeeattachments`, CONSTRAINT `FK1bg8o3b2i8q2wt3vofib6n2f5` FOREIGN KEY (`employeeEmailId`) REFERENCES `employeeemail` (`employeeEmailId`))
2019-12-08 01:51:54.540 INFO 2876 --- [nio-8080-exec-9] o.h.e.j.b.internal.AbstractBatchImpl : HHH000010: On release of batch it still contained JDBC statements
org.springframework.orm.jpa.JpaSystemException: org.hibernate.exception.ConstraintViolationException: could not execute statement; nested exception is javax.persistence.PersistenceException: org.hibernate.exception.ConstraintViolationException: could not execute statement
at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:408)
at org.springframework.orm.jpa.DefaultJpaDialect.translateExceptionIfPossible(DefaultJpaDialect.java:128)
at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:242)
at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:547)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:744)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:712)
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:631)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:385)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:99)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:178)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
at com.sun.proxy.$Proxy120.delete(Unknown Source)
at core.gourabix.services.EmployeeEmailServiceImpl.deleteEmployeeEmail(EmployeeEmailServiceImpl.java:25)
at core.gourabix.controllers.EmployeeEmailController.deleteEmployeeEmail(EmployeeEmailController.java:40)
at sun.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.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:106)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:888)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:793)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:660)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:108)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:526)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:367)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:860)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1591)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:748)
Caused by: javax.persistence.PersistenceException: org.hibernate.exception.ConstraintViolationException: could not execute statement
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:154)
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:181)
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:188)
at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1348)
at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:435)
at org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:3221)
at org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:2389)
at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:447)
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.beforeCompletionCallback(JdbcResourceLocalTransactionCoordinatorImpl.java:183)
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.access$300(JdbcResourceLocalTransactionCoordinatorImpl.java:40)
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commit(JdbcResourceLocalTransactionCoordinatorImpl.java:281)
at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:101)
at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:534)
... 70 more
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:113)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:99)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:200)
at org.hibernate.engine.jdbc.batch.internal.NonBatchingBatch.addToBatch(NonBatchingBatch.java:45)
at org.hibernate.persister.entity.AbstractEntityPersister.delete(AbstractEntityPersister.java:3513)
at org.hibernate.persister.entity.AbstractEntityPersister.delete(AbstractEntityPersister.java:3772)
at org.hibernate.action.internal.EntityDeleteAction.execute(EntityDeleteAction.java:100)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:604)
at org.hibernate.engine.spi.ActionQueue.lambda$executeActions$1(ActionQueue.java:478)
at java.util.LinkedHashMap.forEach(LinkedHashMap.java:684)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:475)
at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:348)
at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:40)
at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:108)
at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1344)
... 79 more
Caused by: java.sql.SQLIntegrityConstraintViolationException: Cannot delete or update a parent row: a foreign key constraint fails (`parentchildkeyrelations`.`employeeattachments`, CONSTRAINT `FK1bg8o3b2i8q2wt3vofib6n2f5` FOREIGN KEY (`employeeEmailId`) REFERENCES `employeeemail` (`employeeEmailId`))
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:117)
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:97)
at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122)
at com.mysql.cj.jdbc.ClientPreparedStatement.executeInternal(ClientPreparedStatement.java:953)
at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdateInternal(ClientPreparedStatement.java:1092)
at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdateInternal(ClientPreparedStatement.java:1040)
at com.mysql.cj.jdbc.ClientPreparedStatement.executeLargeUpdate(ClientPreparedStatement.java:1347)
at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdate(ClientPreparedStatement.java:1025)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:197)
... 91 more
非常感谢您阅读这个巨大的问题!如果您需要,请务必要求进一步澄清。
并提前感谢!
编辑:
因此,根据我的反复试验,很明显,出于某种奇怪的原因,当删除来自 Great-Parent 的条目时,Hibernate 会注意首先删除 Great-Parent 的所有子项,但当相同的操作被删除时却没有这样做尝试为中间父母。在这种情况下,它会继续直接删除中间父级,而不先删除其子级。这就是导致所有这些讨厌问题的原因。这可能是什么原因?
解决方案
推荐阅读
- git - Git切换分支忽略分支名称大小写
- c++ - AWS SDK C++ 安装/Embarcadero:CMake 错误 -fPIC
- php - 两个不同变量中的 PHP 数组
- node.js - 我想为每个虚拟应用程序托管 nodejs 实例,在 azure app 服务中只有一个文件夹的物理位置
- graphql - 带有命名空间查询的 Apollo Client 3.0 缓存
- javascript - JavaScript 自动图像幻灯片放映错误
- .net - .NET 的后写缓存的 Redis 可扩展性
- c# - SMTP 服务器需要安全连接。- 控制台应用程序
- css - 仅使用 CSS 的视差:调整前景和背景的滚动速度,使它们同时到达底部
- quickfixj - 修复协议并使用交错的实时消息重新发送?