Hibernate持久层框架使用【五】hibernate表关联

Hibernate配置表关联的方式

一对一(OneToOne)

例如在一张表中,其中有一个列与另一个表对应,并且是唯一对应的关系时就是一对一关系了,通常我们会将这一列作为外键(数据库基础知识),例如新建两张表,一张company表作为公司表,一张Boss表作为老板表,因此这里就是一个公司对应一个老板(公司表里应该要有一个外键列存储老板的id,并且是唯一的),下面使用OneToOne注解配置一下表的关联关系

示例代码:

@Entity(name="company")
public class Company {
	
	@Id
	@GeneratedValue(strategy=GenerationType.AUTO)
	private int id;
	
	private String name;
	
	private int number;
	
	@OneToOne(fetch=FetchType.LAZY,targetEntity=Boss.class)
	@JoinColumn(name="C_B",unique=true,referencedColumnName="id")
	private Boss boss;

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

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

	public int getNumber() {
		return number;
	}

	public void setNumber(int number) {
		this.number = number;
	}

	public Boss getBoss() {
		return boss;
	}

	public void setBoss(Boss boss) {
		this.boss = boss;
	}
}

这是第一张表,因为要关联Boss表,所以加入了一个Boss属性。在@OneToOne注解中,有两个属性,第一个fetch表示加载的方式,FetchType.LAZY表示延迟加载,即当你获取这张表(Company表)的信息时,只会拿到Company表的信息,只有在使用到Boss表的信息时Hibernate才会根据这条数据对应的外键去Boss表查询(这么做有助于提高性能)

还有一个注解@JoinColumn(name="C_B",unique=true,referencedColumnName="id"),即在表中加入了一个列(外键列),name属性申明列名,unique申明唯一性,referencedColumnName表示这个列对应Boss表中的id列

完成后记得在配置文件里配置这两张表的映射

测试类代码:

OnToOne.class

public class OnToOne {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		MySessionFactory mySessionFactory = new MySessionFactory();
		Session session = mySessionFactory.getSession();
		
		Boss boss = new Boss();
		boss.setName("马化腾");
		session.save(boss);
		
		Company company = new Company();
		company.setName("Tencent");
		company.setNumber(2000);
		company.setBoss(boss);
		session.save(company);
		
		mySessionFactory.commit();
		mySessionFactory.close();
	}

}

测试代码中对两张表各插入了一条数据,必须先插入Boss数据,再拿到这条数据给Company保存,因为后面插入Company数据时还要保存这条数据的外键(Boss这条数据保存时已经变为持久化状态,是有id的)

运行后查看结果,保存成功。如果要测试它的延迟加载机制FetchType.LAZY,可以从Company表中将这条数据取出来,再取出其中的信息(除Boss中的属性)时,控制台只打印了查询Company表的sql语句,而当取出Boss中的信息时,可以看到控制台打印了两条sql语句

一对多(OneToMany)

接下来是表数据一对多的关系,以班级与学生为例:

新建一个Classes类作为班级表:

@Entity(name="classes")
public class Classes {
	@Id
	@GeneratedValue(strategy=GenerationType.AUTO)
	private int cid;
	
	private String name;
	
	@OneToMany(fetch=FetchType.LAZY,
			targetEntity=Student.class,
			orphanRemoval=true
            cascade=CascadeType.REMOVE)
	@JoinColumn(name="FKey_C_S",referencedColumnName="cid")
	private Set<Student> students = new HashSet<>();

	public int getCid() {
		return cid;
	}

	public void setCid(int cid) {
		this.cid = cid;
	}

	public String getName() {
		return name;
	}

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

	public Set<Student> getStudents() {
		return students;
	}

	public void setStudents(Set<Student> students) {
		this.students = students;
	}
}

除了一些基本注解外,需要了解这里的OneToMany注解

@OneToMany(

fetch=FetchType.LAZY, //这个属性即前面写过的懒加载(延迟加载)
targetEntity=Student.class, //这个属性对应实体目标,即对应下面的学生表Student.class
orphanRemoval=true,  //删除孤儿记录,下面会测试

cascade=CascadeType.REMOVE //级联删除

)

下面建立Student类作为学生表:

@Entity(name="student")
public class Student {
	@Id
	@GeneratedValue(strategy=GenerationType.AUTO)
	private int sid;
	
	private String name;
	
	private int age;

	public int getSid() {
		return sid;
	}

	public void setSid(int sid) {
		this.sid = sid;
	}

	public String getName() {
		return name;
	}

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

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}
}

写完后还需要在配置文件中配置两张表的映射

测试类代码示例:

public class OnToMany {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		MySessionFactory mySessionFactory = new MySessionFactory();
		Session session = mySessionFactory.getSession();
		
		Student student1 = new Student();
		student1.setName("关羽");
		student1.setAge(20);
		
		Student student2 = new Student();
		student2.setName("秦琼");
		student2.setAge(21);
		
		Classes classes1 = new Classes();
		classes1.setName("一班");
		classes1.getStudents().add(student1);
		classes1.getStudents().add(student2);
		
		session.save(student1);
		session.save(student2);
		session.save(classes1);
		
		mySessionFactory.commit();
		mySessionFactory.close();
	}

}

运行保存成功,数据表student中保存了两条数据,classes表中保存了一条数据

这里classes表中我们保存的班级那条数据已经跟student表的两条数据关联了,因此可以通过查询这条班级数据来获得关联它的学生数据

示例代码:

public class OnToMany {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		MySessionFactory mySessionFactory = new MySessionFactory();
		Session session = mySessionFactory.getSession();
		
		
		
		//查出班级Id为1的数据
		Classes classes2 = (Classes) session.get(Classes.class, 2);
		System.out.println("学生个数="+classes2.getStudents().size());
		
		mySessionFactory.commit();
		mySessionFactory.close();
	}

}

运行后控制台打印显示Set集合中有两条数据

测试孤儿删除,即可以通过班级来删除它所关联下的所有学生数据

public class OnToMany {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		MySessionFactory mySessionFactory = new MySessionFactory();
		Session session = mySessionFactory.getSession();

		Classes classes1 = (Classes) session.get(Classes.class, 2);
		classes1.getStudents().clear();
		
		mySessionFactory.commit();
		mySessionFactory.close();
	}

}

运行后成功将数据表中关联班级1的两条数据删除

测试级联删除,即在删除班级1时,会同时删除关联了这条数据的学生数据

示例代码:

Classes classes1 = (Classes) session.get(Classes.class, 1);
session.delete(classes1);

猜你喜欢

转载自blog.csdn.net/weixin_39885435/article/details/82934919