1、Hibernate多表操作
关系型数据库具有三种常用关系:
一对一
关系、
一对多
关系和
多对多
关系。
建立了一对多关系的表之间,
一方中的表叫
“
主表
”
,多方中
的表叫
“
子表
”
;两表中相关联的字段,在主表中叫“
主键
”,在子表中称“
外键
”。
一对多关系操作
我们以院系表与学生表为例。在Hibernate映射中,在院系表中添加一个集合属性,集合属性存放该院系下的学生。学生表中将院系编号字段映射成一个院系类对象。这样通过院系类对象的属性集合找到该院系下的所有学生。通过学生对象的院系属性也很快定位到院系的其它信息不仅仅是院系编号。
2、Hibernate多表操作
<hibernate-mapping>
<class name="bean.Student" table="student" catalog="support">
<id name="sno" type="java.lang.String">
<column name="sno" length="4" />
<generator class="assigned"></generator>
</id>
<!--name设定待映射的持久化类的属性名-->
<!--column设定和持久化类的属性对应的表的外键-->
<!--class设定持久化类的属性的类型-->
<many-to-one name="dept" class="bean.Dept"
fetch="select">
<column name="deptid" length="4" />
</many-to-one>
<property name="sname" type="java.lang.String">
<column name="sname" length="20" />
</property>
</class>
</hibernate-mapping>
Dept.hbm.xml
<hibernate-mapping>
<class name="bean.Dept" table="dept" catalog="support">
<id name="deptid" type="java.lang.String">
<column name="deptid" length="4" />
<generator class="assigned"></generator>
</id>
<property name="deptname" type="java.lang.String">
<column name="deptname" length="30" />
</property>
<!-- name
设定待映射的持久化类的属性名
-->
<set name="students" inverse="true">
<!--
所关联的持久类对应的表的外键
-->
<key>
<column name="deptid" length="4" />
</key>
<!--
设定持久化所关联的类
-->
<one-to-many class="bean.Student" />
</set>
</class>
</hibernate-mapping>
测试一对多关系操作
Session s=HibernateSessionFactory.getSession();
Query q=s.createQuery("from Dept");
List l=q.list();
for(int i=0;i<l.size();i++){
Dept dept=(Dept)l.get(i);
System.out.println(dept.getDeptid());
Set stu= dept.getStudents();//
通过院系实例可以
查询该院学生
Iterator it=stu.iterator();
while(it.hasNext()){
Student st=(Student)it.next();
System.out.print(st.getSno()+" ");
}
}
级联操作与延迟加载
1
、
cascade
级联操作
所谓cascade,如果有两个表,在
更新一方的时候,可以根据对象之间的关联关系,
对被关联方进行相应的更新。比如说院系表和学生表之间是一对多关系,使用cascade, 如删除院系表中的一条院系记录时,该院系下的所有学生记录也自动删除。这种现象称为
级联删除。当创建一个新的院系实例,该院系实例集合属性中保存有学生。当该院系实例持久化时,自动将集合学生也自动添加到数据库的学生表中去。这称为
级联增加。
all : 所有情况下均进行关联操作。
none
:所有情况下均不进行关联操作。这是
默认值。
save-update:执行save/update/saveOrUpdate时进行关联操作
delete
:在执行delete时进行关联操作。
2例:
级联示例
删除院系表dept同时将该院系下所有学生student删除。可以在院系类
映射文件中如下定义。
<!--表示级联删除-->
<set name="students" inverse="false"
cascade="delete">
<key>
<column name="deptid" length="4" />
</key>
<one-to-many class="bean.Student" />
</set>
还可以定义级联增加、修改等
<set name="students" inverse="false"
cascade=
"none|all|delete| save-update">
<key>
<column name="deptid" length="4" />
</key>
<one-to-many class="bean.Student" />
</set>
3、
inverse
属性
这个属性不好理解,打个比方来说这个属性。
一个学校有个校长,学校里有很多学生。学生表中假设有一个字段是校长编号(多方),如果我们增加一个学生,学生记录中校长编号字段如何填呢?显然学生自己填(即由学生方维护)要容易些,学生记住校长现实点。如果你要让校长填写学生的校长编号这个字段(即由校长方维护)则比较难,因为校长如何记住那么多学生呢?
例 inverse属性示例.
(
没有采用
inverse)
Team.hbm.xml代码如下(省略部分):
<class name="bean.Team" table="TEAM" >
<set name="students" cascade="all">
<key>
<column name="TEAM_ID" length="20" />
</key>
<one-to-many class="bean.Student" />
</set>
</class>
Student.hbm.xml代码如下(省略部分):
<class name=" bean.Student" table="STUDENT" >
<many-to-one name="team" class="bean.Team" fetch="select">
<column name="TEAM_ID" length="20" />
</many-to-one>
</class>
从上面的代码中没有出现一个inverse关键字,证明维护关系由班级表和学生表一起来维护。比如:现在有新的学生要进入某一个班级(班级号t001),可以
编写如下的代码来完成该功能。
Session session = HibernateSessionFactory.getSession();
Transaction tran = session.beginTransaction();
Query query = session.createQuery("from Student");
List list = query.list();
Team team = (Team) session.get(Team.class, "t001");
for (int i = 0; i < list.size(); i++) {
Student stu = (Student) list.get(i);
if (stu.getTeam() == null) {
team.getStudents().add(stu);
}
}
tran.commit();
这段代码
通过班级来添加学生信息的,也就是说添加学生信息可以由班级来维护。
例 现在只给出Team.hbm.xml配置文件,其中添加了inverse关键,学生映射文件未变。
<class name="bean.Team" table="TEAM" >
<set name="students"
inverse="true"cascade="all">
<key>
<column name="TEAM_ID" length="20" />
</key>
<one-to-many class="bean.Student" />
</set>
</class>
按照上面的配置信息,如果还是想完成新的学生要进入某一个班级(如班级号为t001的班级)这个功能,代码编写如下:
Session session = HibernateSessionFactory.getSession();
Transaction tran = session.beginTransaction();
Query query = session.createQuery("from Student");
List list = query.list();
Team team = (Team) session.get(Team.class, "t001");
for (int i = 0; i < list.size(); i++) {
Student stu = (Student) list.get(i);
if(stu.getTeam() == null) {
stu.setTeam(team);//学生自己维护班级
}
}
tran.commit();
这段代码
通过学生来添加班级信息的,也就是说添加学生信息可以由学生自己来维护。
3
、延迟加载
(1) 属性的延迟加载
如Person表有一个人员图片字段(对应java.sql.Clob类型)属于大数据对象,当我们加载该对象时,我们
不得不每一次都要加
载这个字段,而不论我们是否真的需要它,而且这种大数据对象的读取本身会
带来很大的性能开销。我们
可以如下配置我们的实体类的
映射文件:
<hibernate-mapping>
<class name="bean.Person" table="person">
……
<property name="pimage" type="java.sql.Clob"
column="pimage"
lazy="true"/>
</class>
</hibernate-mapping>
多对多关系操作
以学生与教师为例,一个教师可以教对个学生,一个学生也可以接受多个老师的教育。所以他们之间是多对多的关系。我们一般建立3个表:学生表、教师表以及学生教师表。
学生类映射文件
<class name="Student">
......
<!--
name="teachers" 表示:
Student类中有一个属性叫
teachers (是Set集合)-->
<!--
table="teacher_student" 表示:中间关联表。表名叫
teacher_student -->
<set name="teachers" table="teacher_student">
<!--
column="student_id" 表示:
中间表
teacher_student
的字段-->
<!--
Student类的
id与中间表
teacher_student的字段
student_id对应-->
<key column="student_id"/>
<!--
column="teacher_id" 表示:
中间表
teacher_student
的字段-->
<!--
class="Teacher" 表示:
中间表
teacher_student
的字段
teacher_id
与
Teacher
类的
id
对应-->
<many-to-many
class="Teacher
”
column="teacher_id"/>
</set>
</class>
教师类映射文件
<class name="Teacher">
......
<set name="students" table="teacher_student">
<key column="teacher_id"/>
<many-to-many
class="Student"
column="student_id"/>
</set>
</class>
注意:把多对多关联
分解为
两个
一对多关联,具有更好的可扩展性和操作性。
Hibernate
缓存技术
一、 缓存是介于物理数据源与应用程序之间,缓存被广泛用于数据库应用领域。缓存的设计就是为了
通过存储
已经从数据库读取的数据来减少应用程序和数据库之间
的数据流量
,而数据库的访问只在检索的数据不在当前缓存的时候才需要。
1
、
Hibernate
缓存范围以及分类 (缓存的范围分为三类)
(1)
事务范围:缓存只能被当前事务访问。缓存的生命周期依赖于事务的生命周期,当事务结束时,缓存也就结束生命周期。在此范围下,缓存的介质是内存。事务可以是数据库事务或者应用事务,每个事务都有独自的缓存。
(2)
应用范围:缓存被应用范围内的所有事务共享的。这些事务有可能是并发访问缓存,因此必须对缓存采取必要的事务隔离机制。缓存的生命周期依赖于应用的生命周期,应用结束时,缓存也就结束了生命周期,二级缓存存在于应用范围。
(3)
集群范围:在集群环境中,缓存被一个机器或者多个机器的进程共享。缓存中的数据被复制到集群环境中的每个进程节点,进程间通过远程通信来保证缓存中的数据的一致性,缓存中的数据通常采用对象的松散数据形式,二级缓存也存在与应用范围。
Hibernate
中提供了两级
Cache
。
第
1
级别的缓存是
Session
级别的缓存,即
上述事务范围以及
应用范围的缓存。这一级别的缓存
由
Hibernate
管理的,一般无需进行干预;缓存的
物理介质为内存,由于内存容量有限,必须通过恰当的检索策略和检索方式来
限制加载对象的数目。
第
2
级别的缓存是
SessionFactory
级别的缓存,属于
进程范围或
群集范围的缓存。这一级别的缓存
可以进行配置和更改,并且可以
动态加载和卸载。 第2级缓存的
物理介质可以是内存和硬盘,因此第2级缓存可以存放大量的数据,
数据过期策略的
maxElementsInMemory
属性值可以控制内存中的对象数目。
Hibernate本身并不提供2级缓存的产品化实现,而是
为众多支
持
Hibernate
的第三方缓存组件提供整合接口。