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

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

两个类用户信息和用户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");
    }
}

      


        

版权声明:本文为博主原创文章,未经博主允许不得转载。