JPA记事本

cascade

JPA的关系注解,ManyToMany、OneToOne、ManyToOne等,都有一个cascade属性,指向一组CascadeType枚举值。

public enum CascadeType { ALL, PERSIST, MERGE, REMOVE,REFRESH,DETACH }

这些值将决定当前操作实体中的另一个实体引用字段,与实际持久化数据不一致时,是否级联更新。

默认等效于空,即 @ManyToMany(cascade = {})。ALL表示包含所有。具体枚举用处和使用场景去网上查阅,这里不再解释。

JPA实体的生命周期

JPA 实体的生命周期分为四种状态:新建(New/Transient)、托管(Managed)、脱管(Detached)和删除(Removed)。

状态转换图:

新建 ─────persist()────→ 托管 ───remove()───→ 删除
        ↑                  ↑↓
        │                  │
        └──────merge()────┘
               detach()

CascadeType需要注意的点

默认情况下cascade为空,所以不会执行任何关联更新。这种情况下,更新实体时不会关联更新引用实体的信息,即只更新当前实体和实体间的关系(对应数据库中关系表)。常见的场景,如通过HTTP接口接收JSON数据或Spring Data仓库数据初始化,若有如下格式:

[ { "_class": "org.ximinghui.study.User", "userId": "8f3e", "username": "ximinghui", "password": "123456", "firstName": "Xi", "lastName": "Minghui", "sex": "MALE", "birthday": "1998-01-01", "lastLoginTime": "2024-11-04T23:27:31+00:00", "userGroups": [], "permissionSets": [ { "number": 1, "_remark": "只能在这里添加主键进行关系维护,并不能通过添加权限集的其它属性来实现更新权限集目的", "name": "New Name", "permissions": ["ALL_PERMISSIONS"] } ], "isEnabled": true } ]

即使数据中指定了PermissionSet对象的name和permissions属性,JPA也不会更新PermissionSet实体,它只会维护该User实体和number为1的PermissionSet实体间的关系。

但是,如果设置了CascadeType包含级联更新后,如下:

// ... public class User{ // ... @ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL) // private Set<PermissionSet> permissionSets = new LinkedHashSet<>(); // ... }

这会导致上面的示范JSON数据级联更新PermissionSet实体,因此在设计cascade请考虑到可能存在的安全隐患和意外的实体更新情况!!!