Hibernate注解中的manytomany级联与不级联删除问题的解决

时间:2022-11-07 22:09:12

两个类用户信息和用户Tag类型  多对多的关系

1.用户信息类

package com.yunmiao.bean.player;

import java.util.Date;
import java.util.HashSet;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Table;

import org.hibernate.annotations.Cascade;
import org.springframework.format.annotation.DateTimeFormat;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.yunmiao.bean.base.BaseModel;

/**
* @ClassName: PlayerBindInfo
* @Description: 玩家绑定的个人信息
* @author Jay He
* @date 2015年8月31日 上午11:13:35
*
*/
@Entity
@Table(name="player_bind_info", catalog="vgame")
public class PlayerBindInfo extends BaseModel{

private static final long serialVersionUID = 9138118201233047164L;

// 跟服务器关联的用户名 规则: agentId-serverId-用户id
private String uname;
private Set<PlayerTagType> tags = new HashSet<>();
// 用户真实姓名
private String name;
//性别
private short sex;
//年龄
private Integer age;
// 生日
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8") //取日期时使用
@DateTimeFormat(pattern = "yyyy-MM-dd")//存日期时使用
private Date birthday;
// 电话
private String phone;
// Email
private String email;
// QQ
private String qq;

public String getUname() {
return uname;
}
public void setUname(String uname) {
this.uname = uname;
}

@ManyToMany(cascade = { CascadeType.PERSIST }, targetEntity = PlayerTagType.class, fetch = FetchType.EAGER)
@JoinTable(name = "palyer_info_tag", joinColumns = { @JoinColumn(name = "player_info_id", updatable = true) }, inverseJoinColumns = { @JoinColumn(name = "tag_id", updatable = true) })
@Cascade(value = { org.hibernate.annotations.CascadeType.SAVE_UPDATE })
public Set<PlayerTagType> getTags() {
return tags;
}
public void setTags(Set<PlayerTagType> tags) {
this.tags = tags;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public short getSex() {
return sex;
}
public void setSex(short sex) {
this.sex = sex;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getQq() {
return qq;
}
public void setQq(String qq) {
this.qq = qq;
}
}


2.用户信息Tag类型类


package com.yunmiao.bean.player;

import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Table;

import org.hibernate.annotations.Cascade;

import com.yunmiao.bean.base.BaseModel;

/**
* @ClassName: PlayerTagType
* @Description: 玩家绑定个人信息的Tag类型,即组别
* @author Jay He
* @date 2015年8月31日 上午11:14:47
*
*/
@Entity
@Table(name = "player_bind_tag", catalog = "vgame")
public class PlayerTagType extends BaseModel {
private static final long serialVersionUID = -1798421553058039290L;
// Tag名称
private String name;
// Tag唯一的Code标识
private String code;
// 描述
private String description;
// Tag下的所有玩家
private List<PlayerBindInfo> players;

@Column(name = "name")
public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

@Column(name = "code")
public String getCode() {
return code;
}

public void setCode(String code) {
this.code = code;
}

@Column(name = "description")
public String getDescription() {
return description;
}

public void setDescription(String description) {
this.description = description;
}

/*
* 这里的mappedBy标识在另一方的多对多中,本类被引用的Set的名称,这里是tags
* cascade={CascadeType.REMOVE,CascadeType.PERSIST} -- 表示级联删除和级联保存
*/
@ManyToMany(cascade={CascadeType.MERGE,CascadeType.PERSIST},
mappedBy = "tags", targetEntity = PlayerBindInfo.class)
public List<PlayerBindInfo> getPlayers() {
return players;
}

public void setPlayers(List<PlayerBindInfo> players) {
this.players = players;
}

}


3.关于两侧的manytomany的说明

1.信息表
  

@ManyToMany(cascade = { CascadeType.PERSIST }, targetEntity = PlayerTagType.class, fetch = FetchType.EAGER)
@JoinTable(name = "palyer_info_tag", joinColumns = { @JoinColumn(name = "player_info_id", updatable = true) }, inverseJoinColumns = { @JoinColumn(name = "tag_id", updatable = true) })
@Cascade(value = { org.hibernate.annotations.CascadeType.SAVE_UPDATE })
public Set<PlayerTagType> getTags() {
return tags;
}

cascade:配置级联操作        ---   根据实际情况进行配置

 CascadeType. PERSIST 级联持久化 ( 保存 ) 操作 
CascadeType. MERGE 级联更新 ( 合并 ) 操作 
CascadeType. REFRESH 级联刷新操作,只会查询获取操作 
CascadeType. REMOVE 级联删除操作 

CascadeType. ALL 级联以上全部操作    ---- 默认


JoinTable  : 配置中间表

      name      :   中间表表名

      joinClolumns   : 当前类在中间表中的外键字段

      inverseJoinColumns : 另一个被关联表在中间表中的外键字段



2.Tag表

 @ManyToMany(cascade={CascadeType.MERGE,CascadeType.PERSIST},
mappedBy = "tags", targetEntity = PlayerBindInfo.class)
public List<PlayerBindInfo> getPlayers() {
return players;
}

cascade   : 级联操作  --- 同上面一样

mappedBy  :  本类在另一个类中的引用名称,在Info类中是 private Set<PlayerTagType> tags = new HashSet<>();   所以这里陪只为 tags

targetEntity :  mappedBy 的类型   --- 即tags所在的那个类




我这里的需求是       ---- 级联删除与不级联删除


1.级联删除   即: 删除Tag表的记录后,用户信息表与该Tag关联的也全部删掉

   修改Tag表manytomany为 cascade={CascadeType.ALL}或者添加CascadeType.REMOVE   ----  表示级联删除

@ManyToMany(cascade={CascadeType.MERGE,CascadeType.PERSIST,<span style="font-family: Arial, Helvetica, sans-serif;">CascadeType.REMOVE</span>},
mappedBy = "tags", targetEntity = PlayerBindInfo.class)
public List<PlayerBindInfo> getPlayers() {
return players;
}

2.非级联删除  即:删除Tag表的记录后,只删除中间表中与该Tag有关的记录,而不删除用户信息表中记录  ---  删除Tag,不影响Info表

     1. 修改Tag表中的manytomany  去掉 CascadeType.REMOVE,注意不能在使用CascadeType.ALL(这个事默认配置,表示级联删除) 

     2. 修改表结构,去数据库中设置外键中间表的关联关系为delete cascade,如下图,将中间表的tag_id的删除时由RESTRICT改为CASCADE即可

        Hibernate注解中的manytomany级联与不级联删除问题的解决


3.测试代码

       

import java.util.HashSet;
import java.util.Set;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.yunmiao.bean.player.PlayerBindInfo;
import com.yunmiao.bean.player.PlayerTagType;
import com.yunmiao.service.player.PlayerBindInfoService;
import com.yunmiao.service.player.PlayerTagTypeService;


@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:/spring/*.xml")
public class PlayerTest {

@Autowired
private PlayerBindInfoService playerService;
@Autowired
private PlayerTagTypeService tagService;

@Test
public void test1(){

Set<PlayerTagType> set = new HashSet<>();

PlayerTagType tag = new PlayerTagType();
tag.setName("VIP");
tag.setCode("vip");
tag.setDescription("VIP组");

//tagService.save(tag);

set.add(tag);


PlayerBindInfo info = new PlayerBindInfo();
info.setAge(10);
info.setEmail("3rel23j4@qq.com");
info.setQq("32432434");
info.setPhone("23434322222222");
info.setTags(set);
playerService.save(info);

}

@Test
public void test2(){
tagService.delete(PlayerTagType.class, "402881f34f8293fe014f82940bd90001");
}
}