以学生和课程之间的关系为例
学生表为t_student,课程表为t_course
这里以Student实体类控制关联关系
1.编写实体类 Student
/**
* Hibernate的注解类包名为javax.persistence
*/
@Entity // 将一个Java类声明为一个POJO类(实体类)
@Table(name = "t_student")//声明了该实体映射所指定的表,该类属性name指定表名
public class Student implements java.io.Serializable {
private Integer studentId;
private String studentName;
private String sex;
private String age;
private Set<Course> cous = new HashSet<Course>();
public Student() {
}
public Student(String studentName, String sex, String age) {
this.studentName = studentName;
this.sex = sex;
this.age = age;
}
@Id //声明了该实体的标识属性,该属性对应表中的主键
@GeneratedValue(strategy = GenerationType.IDENTITY)//声明了主键的生成策略为自增长,默认值为GenerationType.AUTO
@Column(name = "student_id") //声明了属性到列的映射
public Integer getStudentId() {
return studentId;
}
public void setStudentId(Integer studentId) {
this.studentId = studentId;
}
@Column(name = "student_name") //声明了属性到列的映射
public String getStudentName() {
return studentName;
}
public void setStudentName(String studentName) {
this.studentName = studentName;
}
@Column(name = "s_sex") //声明了属性到列的映射
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
@Column(name = "s_age") //声明了属性到列的映射
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
@ManyToMany(fetch = FetchType.LAZY, targetEntity = Course.class, cascade = CascadeType.ALL)
@JoinTable(name = "stu_cou", joinColumns = { @JoinColumn(name = "student_id") },
inverseJoinColumns = {@JoinColumn(name = "course_id") })
public Set<Course> getCous() {
return cous;
}
public void setCous(Set<Course> ones) {
cous = ones;
}
}
2.编写实体类 Course
package com.zr.obj;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
@Entity // 将一个Java类声明为一个POJO类(实体类)
@Table(name = "t_course")//声明了该实体映射所指定的表,该类属性name指定表名
public class Course implements java.io.Serializable {
private Integer courseId;
private String courseName;
private String teacher;
private String classroom;
private Set<Student> stus = new HashSet<Student>();
/**
*无参构造方法
*/
public Course() {
}
/**
*有参构造方法
*/
public Course(String courseName, String teacher, String classroom) {
this.courseName = courseName;
this.teacher = teacher;
this.classroom = classroom;
}
@Id //声明了该实体的标识属性,该属性对应表中的主键
@GeneratedValue(strategy = GenerationType.IDENTITY) //声明了主键的生成策略为自增长,默认值为GenerationType.AUTO
@Column(name = "course_id") //声明了属性到列的映射
public Integer getCourseId() {
return courseId;
}
public void setCourseId(Integer courseId) {
this.courseId = courseId;
}
@Column(name = "course_name")//声明了属性到列的映射
public String getCourseName() {
return courseName;
}
public void setCourseName(String courseName) {
this.courseName = courseName;
}
@Column(name = "c_teacher")//声明了属性到列的映射
public String getTeacher() {
return teacher;
}
public void setTeacher(String teacher) {
this.teacher = teacher;
}
@Column(name = "c_classroom")//声明了属性到列的映射
public String getClassroom() {
return classroom;
}
public void setClassroom(String classroom) {
this.classroom = classroom;
}
// mappedBy属性指定关联对象的属性名,表明由对方Order维护关联关系
@ManyToMany(targetEntity = Student.class, fetch = FetchType.LAZY, mappedBy = "cous", cascade = CascadeType.ALL)
public Set<Student> getStus() {
return stus;
}
public void setStus(Set<Student> stus) {
this.stus = stus;
}
}
3.编写测试文件 DemoManyToMany
package com.zr.test;
import org.hibernate.Session;
import org.hibernate.Transaction;
import com.zr.obj.Course;
import com.zr.obj.Student;
import com.zr.util.HibernateSessionFactory;
public class DemoManyToMany {
public static void main(String[] args) {
save();
System.out.println("操作成功!!!");
}
public static void save() {
Session session = HibernateSessionFactory.getSession();//建立会话工厂,获得会话!
Transaction t = session.beginTransaction();// 事务。事务的四大特性:原子性,一致性,隔离性,持久性
Course c1 = new Course("大学高数", "张老师", "101室");
Course c2 = new Course("大学英语", "朱老师", "122室");
Course c3 = new Course("体育", "唐老师", "221室");
Student s1 = new Student("朱振德", "男", "22");
Student s2 = new Student("唐婧", "女", "18");
//建立s1与c1、c2的关联关系
s1.getCous().add(c1);
s1.getCous().add(c2);
s1.getCous().add(c3);
//建立s2与c2、c3的关联关系
s2.getCous().add(c2);
s2.getCous().add(c3);
//由于Student控制关联关系,保存Student实体即可
session.save(s1);
session.save(s2);
t.commit();
session.close();
}
}
4.配置文件
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<!-- Generated by MyEclipse Hibernate Tools. -->
<hibernate-configuration>
<session-factory>
<property name="dialect">
org.hibernate.dialect.MySQLDialect
</property>
<property name="connection.url">
jdbc:mysql://localhost:3306/meitao
</property>
<property name="connection.username">root</property>
<property name="connection.password">123456</property>
<property name="connection.driver_class">
com.mysql.jdbc.Driver
</property>
<property name="myeclipse.connection.profile">mysql</property>
<property name="show_sql">true</property>
<property name="format_sql">true</property>
<mapping class="com.zr.obj.Student" />
<mapping class="com.zr.obj.Course" />
</session-factory>
</hibernate-configuration>
5.知识点汇总
如果没有在属性上添加@Column,则表明该属性所映射字段的名称与其同名 注解既可放在属性上,也可放在属性的getter方法上。
cascade指定对关联实体所采用的级联策略,该级联策略支持如下五个属性值:
CascadeType.ALL包含所有;
CascadeType.PERSIST只有A类新增时,会级联B对象新增。若B对象在数据库存(跟新)在则抛异常(让B变为持久态)
CascadeType.MERGE指A类新增或者变化,会级联B对象(新增或者变化)
CascadeType.REFRESH级联保存:当多个用户同时作操作一个实体,为了用户取到的数据是实时的,在用实体中的数据之前就可以调用一下refresh()方法指定抓取关联实体时的抓取策略,该属性支持以下两个属性值:
FetchType.EAGER:抓取实体时,立即抓取关联实体,这是默认值
FetchType.LAZY:抓取实体时,延迟抓取关联实体,等到真正用到关联实体时才去抓取hibernate 之所以提供与save()功能几乎完全类似的persist()方法,一方面是为了照顾JPA的用法习惯。
另一方面,save()和 persist()方法还有一个区别: 使用 save()
方法保存持久化对象时,该方法返回该持久化对象的标识属性值(即对应记录的主键值); 但使用 persist()
方法来保存持久化对象时,该方法没有任何返回值。 因为 save() 方法需要立即返回持久化对象的标识属性,所以程序执行 save()
会立即将持久化对象对应的数据插入数据库; 而 persist() 则保证当它在一个事物外部被调用时,并不立即转换成 insert 语句,
这个功能是很有用的,尤其当我们封装一个长会话流程的时候,persist() 方法就显得尤为重要了。主要内容区别:
1,persist把一个瞬态的实例持久化,但是并”不保证”标识符(identifier主键对应的属性)被立刻填入到持久化实例中,标识符的填入可能被推迟到flush的时候。
2,save, 把一个瞬态的实例持久化标识符,及时的产生,它要返回标识符,所以它会立即执行Sql insert@JoinTable属性说明
name 指定连接表(中间关系表)的表名
joinColumns 该属性可以接受多个@JoinColumn,用于配置连接表中外键列的列信息,这些外键列参照当前实体的主键列
inverseJoinColumns 该属性可以接受多个@JoinColumn,用于配置连接表中外键列的列信息,这些外键列参照当前实体的关联实体的主键列
6.小秘籍
多对多,两个实体类都要定义对方实体类的集合属性
控制关联关系的一端,配置注解
@ManyToMany(fetch = FetchType.LAZY, targetEntity = Course.class, cascade = CascadeType.ALL)
@JoinTable(name = “stu_cou”, joinColumns = { @JoinColumn(name = “student_id”) }, inverseJoinColumns = {@JoinColumn(name = “course_id”) })不控制关联关系的一端,配置注解
@ManyToMany(targetEntity = Student.class, fetch = FetchType.LAZY, mappedBy = “cous”, cascade = CascadeType.ALL)