双向多对多会通过一个中间表来维持关联关系;
双向多对多关系中必须指定一个关系维护端;否则中间表里会出现主键重复的问题;
可以通过@ManyToMany注释中指定mappedBy属性标识其为关系维护端;
例如:标签类Tags和商品类Goods;一个标签可对应多种商品;一个商品也能有多个标签;
首先在两个类中各建一个对方类型的set作属性;
用到的注解解释:
商品类Goods:
需要用@JoinTable来指定中间表里的属性;
用@ManyToMany来表示关联关系;
//双向多对多映射
@JoinTable(
name="tb_g_to_t",
joinColumns={@JoinColumn(name="g_id",referencedColumnName="gid")},
inverseJoinColumns={@JoinColumn(name="t_id",referencedColumnName="id")}
)
@ManyToMany
private Set<Tags> tagset;
标签表Tags:
用mappedBy指定另一个实体类中代表该类型的映射属性;放弃关联关系;
@ManyToMany(mappedBy="tagset")
private Set<Goods> goodsSet;
1.插入
//插入
@Test
public void testInsert(){
Goods g1=new Goods();
g1.setGname("小米手机");
Goods g2=new Goods();
g2.setGname("苹果手机");
Tags t1=new Tags();
t1.setName("电子产品");
Tags t2=new Tags();
t2.setName("买不起");
//建立关联关系
Set s1=new HashSet();
s1.add(t1);
s1.add(t2);
g1.setTagset(s1);
Set s2=new HashSet();
s2.add(t1);
s2.add(t2);
g2.setTagset(s2);
Set s3=new HashSet();
s3.add(g1);
s3.add(g2);
t1.setGoodsSet(s3);
Set s4=new HashSet();
s4.add(g1);
s4.add(g2);
t2.setGoodsSet(s4);
//保存
manager.persist(g1);
manager.persist(g2);
manager.persist(t1);
manager.persist(t2);
}
结果:
Hibernate:
insert
into
tb_goods
(gname)
values
(?)
Hibernate:
insert
into
tb_goods
(gname)
values
(?)
Hibernate:
insert
into
tb_tags
(name)
values
(?)
Hibernate:
insert
into
tb_tags
(name)
values
(?)
Hibernate:
insert
into
tb_g_to_t
(g_id, t_id)
values
(?, ?)
Hibernate:
insert
into
tb_g_to_t
(g_id, t_id)
values
(?, ?)
Hibernate:
insert
into
tb_g_to_t
(g_id, t_id)
values
(?, ?)
Hibernate:
insert
into
tb_g_to_t
(g_id, t_id)
values
(?, ?)
执行了8条插入语句;
两个实体表各插入两条;中间表插入了四条;
2.查询
无论先查维持关联关系的一端还是先查不会维护关联关系的一端都默认使用懒加载;
因为有一张中间表来做外键映射,对于两张表来说都是平等的;