Hibernate:何时应该使用Cascade.ALL,何时应该单独指定它们?

6

我通常使用CascadeType.ALL来注释我的one-to-manymany-to-manymany-to-one关系,因为它们为我提供了所有我需要的功能。但我感觉这可能会在将来给我带来一些问题。使用CascadeType.ALL是否可以?我应该注意什么,为什么不应该使用它?


4个回答

6

级联操作是指涉及一个对象的持续性动作通过关联操作影响其他对象。

级联操作可以应用于多种Hibernate操作,通常是传递性的。定义关联属性的注释中的"cascade=CascadeType..."属性说明了该关联所要级联的操作。

Cascade = "all"表示应用所有主要的级联类型。

从Hibernate 5.3开始,这些类型包括:

  • "delete" / "remove",
  • "detach" / "evict",
  • "merge",
  • "lock",
  • "persist",
  • "refresh",
  • "replicate",
  • "save_update" / "update"。

(其中一些级联类型名称已经过时或被弃用。)

还有三个复合类型:

  • "all_delete_orphan" - 表示与"all"相同,同时允许删除因级联操作而孤立的实体。
  • "delete_orphan" - 表示"delete"加上孤立实体删除。
  • "none" - 表示不进行级联操作。

你在谈论 Hibernate 提供的 @Cascade 注解。你确定当我在 JPA 注解中使用 cascade 时,它会应用所有 Hibernate 的级联类型吗? - user12099587
JPA 没有所有的级联类型。 这些是 JPA 提供的类型。 级联全部,级联持久化,级联合并,级联删除,级联刷新或级联分离。 - yashjain12yj

4
< p >什么是CascadeType.ALL,何时应该使用?

CascadeType.ALL是所有操作(PERSIST,MERGE,REMOVE,REFRESH,DETACH),它们会传播到关联实体以及持久化上下文中的相关实体。

所以,这个问题非常普遍,如果您知道这些定义,就可以确定是否有必要使用CascadeType.ALL

文档:

EntityManager具有用于持久化新实体、删除(remove)现有实体、从数据存储区刷新实体状态以及将脱离的实体状态合并回持久性上下文的API。

EntityManager执行上述操作时,您可以指示它自动级联操作到具有元数据注释的级联属性中保存的实体。此过程是递归的。级联属性接受一组CascadeType枚举值。

CascadeType.PERSIST: 持久化实体时,也持久化保存在此字段中的实体。我们建议自由使用此级联规则,因为如果EntityManager在flush期间发现引用新实体的字段,并且该字段不使用CascadeType.PERSIST,则会出现错误。

CascadeType.MERGE: 合并实体状态时,也合并保存在此字段中的实体。

CascadeType.REMOVE: 删除实体时,也删除保存在此字段中的实体。

CascadeType.REFRESH: 刷新实体时,也刷新保存在此字段中的实体。

CascadeType.DETACH: 分离实体时,也分离保存在此字段中的实体。

REFERENCES:

EJB3.0规范 - 2.1.7实体关系

Apache-openjpa文档JPA概述Meta Cascade


1
这是你需要理解的内容。首先,你需要了解如何有效地设计数据库,以及你的表格是否独立,或者与另一个表格存在关联。请看下面的要点:
1. 如果你的表格与另一个表格有多个链接,并且在单个表格中持久化数据应该级联到所有依赖表格,则在这种情况下,你必须使用CascadeType.ALL。例如:

EmployeeEntity.java

@Entity
@Table(name = "Employee")
public class EmployeeEntity implements Serializable
{
    private static final long serialVersionUID = -1798070786993154676L;
    @Id
    @Column(name = "ID", unique = true, nullable = false)
    private Integer           employeeId;
    @Column(name = "FIRST_NAME", unique = false, nullable = false, length = 100)
    private String            firstName;
    @Column(name = "LAST_NAME", unique = false, nullable = false, length = 100)
    private String            lastName;

    @OneToMany(cascade=CascadeType.ALL, fetch = FetchType.LAZY)
    @JoinColumn(name="EMPLOYEE_ID")
    private Set<AccountEntity> accounts;

    //Getters and Setters Ommited
}

AccountEntity.java

@Entity
@Table(name = "Account")
public class AccountEntity implements Serializable
{
    private static final long serialVersionUID = 1L;
    @Id
    @Column(name = "ID", unique = true, nullable = false)
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private Integer           accountId;
    @Column(name = "ACC_NO", unique = false, nullable = false, length = 100)
    private String            accountNumber;

    @OneToOne (mappedBy="accounts",  fetch = FetchType.LAZY)
    private EmployeeEntity employee;

}

看一下上面的EmployeeEntity.java源代码。它定义了“cascade=CascadeType.ALL”,这基本上意味着在EmployeeEntity上发生的任何更改都必须级联到AccountEntity上。如果您保存一个员工,那么所有关联的账户也将保存到数据库中。如果您删除一个员工,则与该员工相关的所有账户也将被删除。足够简单。
但是,如果我们只想级联保存操作而不是删除操作。那么我们需要使用下面的代码清楚地指定它。
@OneToMany(cascade=CascadeType.PERSIST, fetch = FetchType.LAZY)
@JoinColumn(name="EMPLOYEE_ID")
private Set<AccountEntity> accounts;

JPA中没有默认的级联类型。默认情况下,不会级联任何操作。


0
除了上述观点外,我还想补充以下几点。 从面向对象编程的角度来看,我们应该考虑组合与聚合的概念。 在Java中,我们无法像在数据库中使用FK键那样强制执行父子关系之间的严格关系。
从概念上讲,Hibernate中的CASCADE选项强制我们维护这种严格关系。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接