假入表中已有如下数据:
现要把张三从 1 班转到 2 班,操作如下:
Session session = HibernateUtil.getCurrentSession();
Transaction transaction = session.beginTransaction();
Student student = session.get(Student.class, 1); // 获取张三
Class clazz = session.get(Class.class, 1); // 获取 2 班
clazz.getStudents().add(student);
student.setClazz(clazz);
transaction.commit();
/*
此时会执行一下两条 SQL:
Hibernate:
update
student
set
name=?,
age=?,
birthday=?,
address=?,
cid=?
where
id=?
Hibernate:
update
student
set
cid=?
where
id=?
*/
可以看到上面示例执行了两条 SQL ,原因是:在上述代码中获取了两个持久态对象,并且在事务提交时两个持久态对象的属性都发生了变化,所以 Hibernate 发出了两条 SQL。
但显然这个操作其实一条 SQL 就能搞定的,这个时候就需要控制一方不维护外键关系了。
**‘一’的一方放弃维护外键关系: **
<!-- com/zze/bean/Class.hbm.xml:修改‘一’(班级)映射文件,在 set 标签中添加属性 inverse="true" -->
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.zze.bean.Class" table="class">
<id name="id">
<generator class="native"/>
</id>
<property name="name" length="32"/>
<set name="students" cascade="save-update" inverse="true">
<key column="cid"/>
<one-to-many class="com.zze.bean.Student" />
</set>
</class>
</hibernate-mapping>
依旧是执行上述代码,会发现只会由‘多’(学生)的一方发出一条 update 语句。
在 Hibernate 中,‘多’的一方不可以放弃维护外键关系。
为什么‘多’的一方不能放弃维护外键关系?换句话说为什么 Hibernate 要让多的一方来维护关系?
原因是当‘一’的一方维护关系时,Hibernate 会额外发出一条 select 语句查出它所关联的所有的多的一方,显然没必要。而多的一方维护关系就比较简单了,直接 update 它本身的外键即可。
看到过一个有趣应景的说法:十三亿人民(‘多’)记住(维护)国家领导人的名字很简单,但要想国家领导人(‘一’)记住(维护)十三亿就不可能了。
理解 inverse 和 cascade:
// com/zze/bean/Class.hbm.xml 的 set 中设置了 cascade="save-update"、inverse="true"
Session session = HibernateUtil.getCurrentSession();
Transaction transaction = session.beginTransaction();
Student student = new Student();
student.setName("王五");
Class clazz = session.get(Class.class, 2); // 获取 1 班
clazz.getStudents().add(student);
session.save(clazz);
transaction.commit();
/*
上述代码执行结果会是怎么样?
先明确 cascade 和 inverse 的作用:
cascade:为 save-update,即 Class 会级联保存和更新 Student。
inverse:为 true,即 Class 放弃维护外键关系。
首先 session 保存的是 clazz,clazz 是持久态对象。
在事务提交时 clazz 的外键字段 students 发生了变化,添加了 student,
班级有级联操作学生的能力,所以“王五”这个 student 会被保存到数据库。
而班级放弃了维护外键关系,所以“王五”这个 student 添加到数据库后对应的外键字段为 null。
结果如下:
mysql> select * from student;
+----+--------+------+----------+---------+------+
| id | name | age | birthday | address | cid |
+----+--------+------+----------+---------+------+
| 1 | 张三 | NULL | NULL | NULL | 1 |
| 2 | 王五 | NULL | NULL | NULL | NULL |
+----+--------+------+----------+---------+------+
2 rows in set (0.00 sec)
*/
评论区