【发布时间】:2019-10-15 05:36:54
【问题描述】:
我将 Spring Boot (2.1.0.RELEASE) 与 Spring Data JPA 一起使用。数据库是 MySQL。
我有一些连锁级联删除的问题。
我有以下型号:
我不使用@ManyToMany,因为我需要在生成的表中添加额外的字段,所以我的实体如下(无用的属性已被删除):
@Audited
@Entity
@Table(name = "request")
public class Request {
@OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true)
private Resource resource;
}
@Audited
@Entity
@Table(name = "resource")
public class Resource {
@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "resource")
private Set<ResourceArticle> resourceArticles;
}
@Audited
@Entity
@Table(name = "resource_article")
public class ResourceArticle {
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "article_id")
private Article article;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "resource_id")
private Resource resource;
@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "resourceArticle")
private Set<ResourceArticleOption> options;
}
@Audited
@Entity
@Table(name = "resource_article_option")
public class ResourceArticleOption {
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "option_id")
private Option option;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "resource_article_id")
private ResourceArticle resourceArticle;
}
然后我的经理发出请求 delete 扩展 CrudRepository :
/* Repositroy */
public interface RequestRepository extends CrudRepository<Request, Long> {
}
/* Manager */
@Transactional
@Component("requestMgr")
public class RequestManager {
@Autowired
RequestRepository requestRepository;
public void delete(Request request) {
requestRepository.delete(request);
}
}
/* Viewmodel */
public class RequestVm {
@WireVariable
private RequestManager requestMgr;
public void deleteRequest(Request req) {
requestMgr.delete(req);
}
}
错误是:
原因:java.sql.SQLException:无法删除或更新父级 行:外键约束失败 (
my_db.resource_article, 约束FK5wqvprkwx05fb5hgt6w9h7nbk外键 (resource_id) 参考resource(id))
启用跟踪时的输出:
delete from request where id=?
binding parameter [1] as [BIGINT] - [24]
delete from resource where id=?
binding parameter [1] as [BIGINT] - [71]
SQL Error: 1451, SQLState: 23000
(conn=30) Cannot delete or update a parent row: a foreign key constraint fails (`my_db`.`resource_article`, CONSTRAINT `FK5wqvprkwx05fb5hgt6w9h7nbk` FOREIGN KEY (`resource_id`) REFERENCES `resource` (`id`))
奇怪的是它试图按request > resource > resource_article > resource_article_option 的顺序删除?
我需要CascadeType.ALL,因为我想坚持和删除。
我可以通过在删除之前设置对null 的引用来打破链条,但当然会导致数据库中出现孤立记录。
这里最好的策略是什么?
【问题讨论】:
-
请注意,您可以级联多个操作而无需级联所有操作。这并不一定意味着您不需要或不需要
CascadeType.ALL,或者使用它会导致您的问题,只是您给出使用它的原因无效(JPA 识别的操作不仅仅是PERSIST和REMOVE). -
据我所知或所知,删除
Resourcevia 扩展CrudRepository的存储库应遵守为父实体声明的 JPA 级联属性。这似乎没有发生,这让我怀疑有些东西不是你所呈现的那样,或者有些重要的东西被遗漏了。也许您的实体的部署版本没有启用级联?也许您已经自定义了您的存储库,使其delete()方法以某种方式绕过 JPA? -
谢谢约翰。确实我说错了,我知道我可以使用多种级联类型,但据我所知,我没有理由不级联所有东西,所以我使用
ALL。我在这里没有介绍的其他属性是基本的@Column,应该不会造成任何问题。我自愿省略的唯一一件事是我在此之上还有另一个表,REQUEST表与RESOURCE具有 1-1 关系,删除是根据此请求完成的。最后请注意,我使用 Envers 进行审计,我的实体有@Audited注释,所以对于每个表我都有另一个xxx_audit_log表。我已经更新了我的帖子。
标签: java hibernate jpa spring-data-jpa cascade