Hibernate的关联关系注解映射(一对一、一对多、多对一、多对多、自连接)

Hibernate注解的关联关系映射,分为2种,即单向关联映射和双向关联映射,它们最大的区别就是在查询数据时,单向关联只能通过一边进行查询,而双向关联两边都可以进行查询。

单向关联是指只在一方加上注解,

双向关联是指双方都加上注解。这里主要记录双向关联。

1,一对多多对一单向关联 
     –@ManyToOne:在多的一方维护记录(在tuser2表维护记录) 


   (1)表结构:tuser2表的groupid字段关联tgroup表的主键id,tuser2是多的一方,tgroup是一的一方:

(2)bean:

@Entity
@Table(name="tuser2")
public class TUser2 implements Serializable{
    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Integer id;

    @Column(name="name")
    private String name;

    @ManyToOne  //代表是一对多关联
    @JoinColumn(name="groupid")  //关联的字段是groupid
    private Group group;
...get,set...
}
//Group不需要写任何东西
@Entity
@Table(name="tgroup")
public class Group implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Integer id;

    @Column(name="name")
    private String name;
...get,set...
}

(3)测试 
–保存记录

Group group=new Group();
group.setName("manager");
TUser2 user=new TUser2();
user.setName("hyman");
user.setGroup(group);
session.save(group);
session.save(user);

–获取记录(此种写法只能从user一方获取group一方的数据)

TUser2 user=(TUser2)session.get(TUser2.class,1);
System.out.println(user.getName());
System.out.println(user.getGroup().getName());

–更新记录

Group group=new Group();
group.setName("name2");
TUser2 user=(TUser2)session.get(TUser2.class, 1);
user.setGroup(group);
session.save(group);
session.save(user);

–删除记录

Group group=(Group)session.get(Group.class, 5);
session.delete(group);
//如果tuser表中存在groupid为5的记录,后台会报错,因为tuser表中引用了groupid,因此不能删除group

TUser2 user=(TUser2)session.get(TUser2.class, 1);
session.delete(user);

–如果在@ManyToOne后面设置了cascade=CascadeType.ALL,那么就有两种情况: 
(1)tuser2不存在相同的groupid的其他记录,此时会删除tuser2表中id为1的记录,也会级联删除group表中相应的记录; 
(2)tuser2表存在相同的groupid的其他记录,后台会报错,无法删除。 
如果没有设置cascade=CascadeType.ALL,则会删除tuser2表的记录,不会删除group表的记录。

–@OneToMany:在一的一方维护记录(在group表维护记录) 


(1)表结构和上面的一样; 
(2)bean:

@Entity
@Table(name="tgroup")
public class Group implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Integer id;

    @Column(name="name")
    private String name;

    @OneToMany(cascade=CascadeType.ALL,fetch=FetchType.LAZY)
    @JoinColumn(name="userid")  //意味着在user表会多出一列userid,如果不设置这个属性,那么会多出一个中间表,表中两个字段分别是group和user表的id
    private Set<TUser2> users;
...get,set...
}
@Entity
@Table(name="tuser2")
public class TUser2 implements Serializable{
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Integer id;

    @Column(name="name")
    private String name;
...get,set...
}

(3)测试: 
–保存记录

TUser2 user21=new TUser2();
user21.setName("name1");
TUser2 user22=new TUser2();
user22.setName("name2");
Set<TUser2> set=new HashSet<>();
set.add(user21);
set.add(user22);
Group group=new Group();
group.setName("groupname");
group.setUsers(set);
session.save(group);

–获取记录

Group group=(Group)session.get(Group.class, 9);
Set<TUser2> users=group.getUsers();
Iterator us=users.iterator();
while(us.hasNext()){
    TUser2 user=(TUser2)us.next();
    System.out.println(user.getName());
}

//只能从group一方获取user一方的数据,而不能从user一方获取group一方的数据

–更新记录

Group group=(Group)session.get(Group.class, 9);
group.setName("updatedName");
session.save(group);

–删除记录

Group group=(Group)session.get(Group.class, 9);
session.delete(group);

如果在@OneToMany后面设置了cascade=CascadeType.ALL,那么会级联删除user表中的记录,如果没有设置,那么会清空user表的groupid字段,然后删除group表记录。

2,一对多多对一双向关联 
上面的一对多或多对一的关联都有一个不足之处,就是只能从一方获取另一方的数据,双向关联下,就可以从任何一方获取另一方的数据了

(1)表结构:

(2)bean:在一的一方需要设置@OneToMany和mappedby,在多的一方需要设置@ManyToOne和

@JoinColumn:

@Entity
@Table(name="tgroup")
public class Group implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Integer id;

    @Column(name="name")
    private String name;

    @OneToMany(cascade=CascadeType.ALL,fetch=FetchType.LAZY,mappedBy="group")
    private Set<TUser2> users;
...set,get...
}
@Entity
@Table(name="tuser2")
public class TUser2 implements Serializable{
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Integer id;

    @Column(name="name")
    private String name;

    @ManyToOne(fetch=FetchType.LAZY,cascade=CascadeType.ALL)
    @JoinColumn(name="groupid") //会在user表中多出一列:groupid,如果不设置这个属性,数据库会新增一个中间表维护user和group的记录
    private Group group;
    ...set,get...
}

(3)测试: 
–保存记录

TUser2 user21=new TUser2();
user21.setName("name1");
TUser2 user22=new TUser2();
user22.setName("name2");
Set<TUser2> set=new HashSet<>();
set.add(user21);
set.add(user22);

Group group=new Group();
group.setName("groupname2");
group.setUsers(set);
user21.setGroup(group);//必须,否则user表groupid字段为空
user22.setGroup(group);//必须,否则user表groupid字段为空
session.save(group);

–获取记录 
(1)从一的一方获取多的一方的记录

Group group=(Group)session.get(Group.class, 9);
Set<TUser2> users=group.getUsers();
Iterator us=users.iterator();
while(us.hasNext()){
    TUser2 user=(TUser2)us.next();
    System.out.println(user.getName());
}

(2)从多的一方获取一的一方的记录:

TUser2 user=(TUser2)session.get(TUser2.class, 18);
System.out.println(user.getGroup().getName());

–更新记录

Group group=new Group();
group.setName("newGroup");  
TUser2 user=(TUser2)session.get(TUser2.class, 18);
user.setGroup(group);
session.save(user);//会自动保存新增的group表的记录

–删除记录

Group group=(Group)session.get(Group.class, 13); session.delete(group);//会级联删除user表中的记录

TUser2 user=(TUser2)session.get(TUser2.class, 3); session.delete(user);//会级联删除group中的相关的记录和user表中的相同groupid的记录

3,多对多单向关联 


(1)表:

 

(2)bean:只在一方维护关系就好,例如在class表一方维护关系,teacher表一方不做处理

@Entity
@Table(name="class")
public class Clazz implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Integer id;

    @Column(name="name")
    private String name;

    @ManyToMany(cascade=CascadeType.ALL,fetch=FetchType.LAZY)
    @JoinTable(
        name="class_teacher",//中间表名
        joinColumns={@JoinColumn(name="classid")},//当前对象id在中间表的列名
        inverseJoinColumns={@JoinColumn(name="teacherid")}//关联的另一个表在中间表的列名
    )
    private Set<Teacher> teachers;
...set,get...
}
@Entity
@Table(name="teacher")
public class Teacher implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Integer id;

    @Column(name="name")
    private String name;
...set,get...
}

(3)测试: 
–保存记录

Clazz clazz1=new Clazz();
Clazz clazz2=new Clazz();
clazz1.setName("class1");
clazz2.setName("class2");
Teacher teacher1=new Teacher();
Teacher teacher2=new Teacher();
Teacher teacher3=new Teacher();
teacher1.setName("teacher1");
teacher2.setName("teacher2");
teacher3.setName("teacher3");
Set<Teacher> teacher1s=new HashSet<>();
Set<Teacher> teacher2s=new HashSet<>();     
teacher1s.add(teacher1);
teacher1s.add(teacher2);
teacher2s.add(teacher2);
teacher2s.add(teacher3);
clazz1.setTeachers(teacher1s);
clazz2.setTeachers(teacher2s);  
session.save(clazz1);//会级联插入class表,teacher表,中间表
session.save(clazz2);//会级联插入class表,teacher表,中间表

–获取记录:由于只在class的乙方做了维护,因此只能从class表记录获取teacher表记录

Clazz clazz=(Clazz)session.get(Clazz.class, 1);
Set<Teacher> teachers=clazz.getTeachers();
Iterator<Teacher> iterator=teachers.iterator();
while(iterator.hasNext()){
    Teacher teacher=iterator.next();
    System.out.println(teacher.getName());
}

–更新记录,更新id为1的class的teachers信息

Clazz clazz=(Clazz)session.get(Clazz.class, 1);
Teacher teacher=(Teacher)session.get(Teacher.class, 1);
Set<Teacher> teachers=new HashSet<>();
teachers.add(teacher);
clazz.setTeachers(teachers);
session.save(clazz);//只更新中间表的id对应关系,插入新记录,删除失效的记录

–删除记录

Clazz clazz=(Clazz)session.get(Clazz.class, 2);
session.delete(clazz);//删除class表记录,删除中间表记录,删除teacher表记录
//注意:如果teacher表中不存在和class对应的其他记录,那么teacher表的相关记录会被删除,如果teacher表中存在和class对应的其他记录,后台会报错,无法删除。

4,多对多双向关联 


上面的多对多但相关联有一个不足就是只能从class来维护teacher表的记录,双向关联则可以从任何一方维护另一方的记录: 
(1)表结构不变; 
(2)bean:class不变,teacher只要设置mappedby属性即可:

@Entity
@Table(name="teacher")
public class Teacher implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Integer id;

    @Column(name="name")
    private String name;

    @ManyToMany(mappedBy="teachers",cascade=CascadeType.ALL,fetch=FetchType.LAZY)
    private Set<Clazz> clazzs;
...set,get...
}

(3)测试: 
–保存记录 
双向关联并不是真的互相维护,还是存在控制权的问题,这里就把控制权交给了class。因此,写法和单向关联是一样的。

–获取记录 
在双向关联中,既可以通过class来获取teacher的记录,也可以通过teacher获取class的记录:

Clazz clazz=(Clazz)session.get(Clazz.class, 1);
Set<Teacher> teachers=clazz.getTeachers();
Iterator<Teacher> iterator=teachers.iterator();
while(iterator.hasNext()){
    Teacher teacher=iterator.next();
    System.out.println(teacher.getName());
}

Teacher teacher=(Teacher)session.get(Teacher.class, 5);
Set<Clazz> clazzs=teacher.getClazzs();
Iterator<Clazz> iterator2=clazzs.iterator();
while(iterator2.hasNext()){
Clazz clazz2=iterator2.next();
System.out.println(clazz2.getName());
}

–更新记录 
双向关联并不是真的互相维护,还是存在控制权的问题,这里就把控制权交给了class。因此,写法和单向关联是一样的。

–删除记录

Teacher teacher=(Teacher)session.get(Teacher.class, 5);
session.delete(teacher);

首先会删除中间表teacherid=17的记录;然后删除teacher表id=17的记录,删除class表相关的记录(不存在与其他teacherid关联的记录),然后删除中间表中classid=6和7的记录,删除class表中id为6和7的记录,删除teacher表中和classid 6,7关联的记录。所以,删除之后的结果是: 

因此,在多对多关联的时候,一定要想清楚自己的目的,不要盲目使用cascadeType.all。否则会删除一些本来不想删除的记录。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值