我们接着上一篇文章结尾的案例讲解Hibernate的文件配置
设置外键维护的方式
修改Customer的配置文件,添加一个inverse选项
Inverse是Hibernate双向关系中基本概念,inverse的真正作用就是指定由哪一方来维护之间的关联关系,当一方中指定了inverse="false"(默认),那么哪一方负责之间的关联关系
cascade级联
-
save-update 级联保存,级联修改,保存A时,同时保存B
Session session = HibernateUtils.openSession();
session.beginTransaction().begin();
Customer customer = new Customer();
customer.setName("April");
customer.getOrders().add(new Order("cheese","TB"+ ((int)(Math.random() * 100000000))));
customer.getOrders().add(new Order("cake","JD"+ ((int)(Math.random() * 100000000))));
customer.getOrders().add(new Order("lipstick","JD"+ ((int)(Math.random() * 100000000))));
customer.getOrders().add(new Order("necklace","JD"+ ((int)(Math.random() * 100000000))));
session.save(customer);
session.beginTransaction().commit();
session.close();
-
delete 级联删除,删除A时,同时删除B,我们现在只需要把cascade的属性值替换成delete即可,然后我们可以删除customer id为5,当我们删除id=5的顾客时,与之关联的订单表的数据也随之被删除
Session session = HibernateUtils.openSession();
session.beginTransaction().begin();
Customer customer = (Customer) session.get(Customer.class,5);
session.delete(customer);
session.beginTransaction().commit();
session.close();
-
delete-orphan孤儿删除,解除关系,同时将B删除,A存在,其实也很好理解,也就是把cascade的属性值设置为delete-orphan,删除某一个的所有订单,客户数据不会被删除,与客户相关的订单会被删除
代码示例
Session session = HibernateUtils.openSession();
session.beginTransaction().begin();
Customer customer = (Customer) session.get(Customer.class,7);
Order order = (Order) session.get(Order.class,13);
customer.getOrders().remove(order);
Order order1 = (Order) session.get(Order.class,14);
customer.getOrders().remove(order1);
Order order2 = (Order) session.get(Order.class,15);
customer.getOrders().remove(order2);
Order order3 = (Order) session.get(Order.class,16);
customer.getOrders().remove(order3);
session.update(customer);
session.beginTransaction().commit();
session.close();
如果需要配置多项,使用逗号隔开
all:save-update和delete的整合、
all-delete-orphan三个的整合
Hibernate的多表关联关系映射
案例:以学生和课程为例,一个学生可以对应多个课程,一个课程可以对应多个学生,也就是多对多的场景
首先我们的创建学生和课程的JavaBean(entity pojo model),然后与之数据库属性对应的hbm.xml映射文件的编写
Student.class
public class Student {
private int sid;
private String username;
private String score;
private Set<Course> courses = new HashSet<>();
public Student() {
}
public Student(String username, String score) {
this.username = username;
this.score = score;
}
public int getSid() {
return sid;
}
public void setSid(int sid) {
this.sid = sid;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getScore() {
return score;
}
public void setScore(String score) {
this.score = score;
}
public Set<Course> getCourses() {
return courses;
}
public void setCourses(Set<Course> courses) {
this.courses = courses;
}
@Override
public String toString() {
return "Student{" +
"id=" + sid +
", username='" + username + '\'' +
", score='" + score + '\'' +
'}';
}
}
Course.class
public class Course {
private int id;
private String name;
private Set<Student> students = new HashSet<>();
public Course() {
}
public Course(int id, String name) {
this.id = id;
this.name = name;
}
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 Set<Student> getStudents() {
return students;
}
public void setStudents(Set<Student> students) {
this.students = students;
}
@Override
public String toString() {
return "Course{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
Student.hbm.xml
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.zzx.hibernate.domain">
<class name="Student" table="t_student">
<id name="id" column="sid">
<generator class="native"></generator>
</id>
<property name="username"></property>
<property name="score"></property>
<set name="courses" table="t_student_course">
<key column="sid"></key>
<many-to-many class="Course" column="cid"></many-to-many>
</set>
</class>
</hibernate-mapping>
Course.hbm.xml
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.zzx.hibernate.domain">
<class name="Course" table="t_course">
<id name="id" column="cid">
<generator class="native"></generator>
</id>
<property name="name"></property>
<set name="students" table="t_student_course">
<key column="cid"></key>
<many-to-many class="Student" column="sid"></many-to-many>
</set>
</class>
</hibernate-mapping>
多对多set的配置
- set中table写中间表的名称
- key中column:写中间表的当前模型key外键的名称
- many-to-many:写中间表的另外一个模型外键的名称
保存学生
需要注意的是:保存前外键和级联是何如配置
一般操作多的一方选择级联,这里的学生操作比较多
Student:
inverse="false",维护外键的关系,由Student维护
cascade="save-update"保存和更新时,都级联
级联配置相关逻辑详解
- 如果在Student配置inverse="true",由Course来维护外键关系,中间表没有数据
- 默认Student配置inverse="false",由Student来维护外键关系,中间表有数据
- 多对多,inverse不能两边都为true,如果两边都为true,不管保存哪一个对象,中间表都没有数据
提交保存时,如果出现乱码。是由于提交时字符集和数据库字符集不一致导致的 - 修改hibernate.cfg.xml
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/hibernate_demo01?characterEncoding=UTF-8</property>
- 创建数据库时指定字符集
create databse hibernate_demo01 character set utf8;
1.3加载策略
1.3.1类级别的加载策略
- get:立即检索,get方法一执行,立即查询所有字段的数据
- load:延迟检索,默认情况load方法执行后,如果只使用OID不查询,其他属性值才查询
如果在类级别上配置lazy为false,那load方法就会立即加载,否则为延迟加载
1.3.2关联级别的加载策略
- 关联级别的集合加载的策略,默认是懒加载
-
可以设置为即使加载,如图几家在学生时,学生所属的课程也会加载进来
多对多配置,配置中间表
- 默认情况下Student下的Course数据只有访问的时候,才会执行SQL
-
在set中配置lazy="false",不用访问Course属性,也会先执行SQL查询语句
1.3.3 fetch 查询集合的sql方式
select:默认的普通select查询语句
join:表连接语句查询,查询数据使用一条SQL语句搞定,使用左外连接
subselect:使用子查询,在条件里由有select语句【只能用于多对多或一对多】
练习:查询每一个学生对应课程
select * from t_student ts inner join t_student_course tsc on ts.sid = tsc.sid inner join t_course tc on tc.cid = tsc.cid;
1.3.4 多对一加载策略
上篇文章我们讲解了多对一的案例,这里我们还是以上篇文案多对一的案例进行进一步的了解其加载策略
多对一的标签<many-to-one fetch="" lazy="">
多对一的set集合加载策略
lazy:false是否懒加载【当加载Order时,与此同时Customer也会被加载】
proxy:根据类级别的加载策略决定
no-proxy:不做研究,用的少
fetch:subselect时不能使用在多对一的,subselect返回的是一个集合
·1.3.5 批量加载
set标签可以配置一个batch-size="2",表示每次可以加载两条数据
执行结果:从结果可以看出在执行SQL语句Order表查询了两次,跟set设置的batch-size="2",两次有关