hibernate cascade的真正含義


hibernate cascade 是 @OneToOne @OneToMany @ManyToOne @ManyToMany等注解的屬性,表示級聯操作。

  /**
     * (Optional) The operations that must be cascaded to
     * the target of the association.
     *
     * <p> By default no operations are cascaded.
     */
    CascadeType[] cascade() default {};

谷歌翻譯對注釋的翻譯

必須級聯到關聯目標的操作。默認情況下沒有級聯操作。

這里解釋一下,級聯的意思是:本實體做了什么事,也要拉上 另一個關聯的實體,導致另一個實體跟着做事情。就是說我刪除了,你也得刪除! 關聯目標,指的是 關聯的那個實體。

 

在有中間關系表的情況下,比如 user/role/user_role 這三張表,只對應User/Role兩個實體對象就夠了!中間表是由User對象或者Role對象維護的,不用另外新建user_role的實體!

user

id name

 

role

id name

 

user_role

user_id role_id

 

@Table(name = "user")
@Entity
public class User
{
    @ManyToMany(fetch = FetchType.LAZY)
    @JoinTable(name = "user_role", joinColumns = {@JoinColumn(name= "user_id")}, inverseJoinColumns = {@JoinColumn(name = "role_id")})
    private Set<Role> roles;


    //get set ...
}
@Entity
@Table(name = "role")
public class Role
{

    @ManyToMany(fetch= FetchType.LAZY)
    @JoinTable(name = "user_role", joinColumns = {@JoinColumn(name= "role_id")}, inverseJoinColumns = {@JoinColumn(name = "user_id")})
    private Set<User> users;

    // get set ...

}

上述是對user,role多對多的關聯關系的配置。cascade沒有寫,即是默認值,就是不級聯的意思。

不級聯就是說,比如在User類中,@ManyToMany沒有寫cascade就是說,User的操作不影響Role的操作,也就是說針對user表的操作不影響role表的記錄。這個和user_role關系表沒關系!user_role表的映射關系的維護,和cascade寫不寫,寫什么值一點關系都沒有!hibernate會給你維護好關系表的記錄的,經測試是先刪除關系記錄,再插入關系記錄。

 

如果,你發現User針對Role屬性的cascade沒有寫,但是修改了role的值,確發生變更了,打印出sql語句,也發現還是級聯更新了,咋回事?

這個我也郁悶了好久,hibernate真心不好用,太復雜了。經過苦心調試終於明白了。不是cascade不寫沒有用,而是你對role的變更是不是先查詢出來的持久對象的操作。這樣的操作是針對Role持久化對象的修改,和級聯沒關系,就是說你直接修改了role對象,當然更新了值!

Set<Role> roles = new HashSet<>();           
for (Long roleId : roleIds)
{
       Role role = roleDAO.get(Role.class, roleId);
       role.setName(role.getName()+"_1"); //測試級聯
       roles.add(role);
}
user.setRoles(roles);
userDao.saveOrUpdate(user);

上述代碼,保存user的時候,即使cascade沒有寫,可是role記錄還是被改變了!原因就是,你通過roleId得到Role的時候,得到的是Role持久化對象,然后你改變了Role的值,那role記錄肯定變更了!這個變更和cascade沒有關系,是你自己變更的,能怪誰!請看下述代碼

Set<Role> roles = new HashSet<>();           
for (Long roleId : roleIds)
{
       Role role = roleDAO.get(Role.class, roleId);
       role.setName(role.getName()+"_1"); //測試級聯
       session.evict(role); //使持久化對象游離
       roles.add(role);
}
user.setRoles(roles);
userDao.saveOrUpdate(user); 

這里就增加了一句代碼,再運行,你會發現,Role值改變了,確實沒有使role記錄發生變更,這說明cascade不寫有用了。這時,你把User類下roles屬性上的casecase改為CascadeType.ALL,再運行你會發現,role記錄又改變了,那這次role的變更才是真正因為是cascade的作用!

 

總結:

1.hibernate實體關系中,cascade屬性表示 實體的操作是否 級聯 到 關聯的實體, 和中間表無關。

2.無論cascade寫不寫,寫什么, 中間表都將被hibernate很好的維護了。

3.cascade不寫,沒有生效,可能是因為你直接對 關聯的實體(持久化的對象) 進行操作了,游離化的 對象就不會有事!

 

所以說,如果你如果不想讓Role的修改影響到User,那你cascade就不要寫,針對User的操作也要注意不要使用持久化的對象(get,load得到的對象,hql得到的是游離化的對象),反之亦然。不用擔心中間表的關系維護! 如果你想讓Role的修改影響到User,那你就寫上cascade的值,級聯就生效了(user對象管它是持久對象還是游離對象)!

 

附錄:

/**
 * Defines the set of cascadable operations that are propagated
 * to the associated entity.
 * The value <code>cascade=ALL</code> is equivalent to
 * <code>cascade={PERSIST, MERGE, REMOVE, REFRESH, DETACH}</code>.
 *
 * @since Java Persistence 1.0
 */
public enum CascadeType {

    /** Cascade all operations 級聯所有操作 */
    ALL,

    /** Cascade persist operation 級聯新增 */
    PERSIST,

    /** Cascade merge operation 級聯更新或者新增 */
    MERGE,

    /** Cascade remove operation 級聯刪除 */
    REMOVE,

    /** Cascade refresh operation 級聯刷新 */
    REFRESH,

    /**
     * Cascade detach operation
     * 級聯分離
     * @since Java Persistence 2.0
     *
     */
    DETACH  
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM