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; } }
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; } }
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即可
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"); } }
版权声明:本文为博主原创文章,未经博主允许不得转载。